email_forward_parser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.standard.yml +3 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +62 -0
- data/README.md +5 -0
- data/Rakefile +14 -0
- data/email_forward_parser.gemspec +33 -0
- data/lib/email_forward_parser/mailbox_parser.rb +82 -0
- data/lib/email_forward_parser/original_email_parser.rb +223 -0
- data/lib/email_forward_parser/parser.rb +57 -0
- data/lib/email_forward_parser/regexes.rb +331 -0
- data/lib/email_forward_parser/utils.rb +33 -0
- data/lib/email_forward_parser/version.rb +5 -0
- data/lib/email_forward_parser.rb +58 -0
- metadata +56 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 108a3d5da682072760ed99217ad68f469c4a600db7452ec60386a6e1f504c791
|
4
|
+
data.tar.gz: ab7efb48ceeeef0f8a27377b56b2a86f0008c00c794005db55de03f326ea9b4e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 32fb415bacbbecc88b045d3b6eb517db25a166670129808186e4ab57b1167ee1b654383ba7c6027426f4b33f5ce8f73bdd101672fd718cbe5f1e20274b3c1ee0
|
7
|
+
data.tar.gz: 85bff86e606bdede3d3905c121c3ceb1fbe76d9ffd369be4df71a2263149a1c7b7ec5fa5819fe2f305dc7d1cc14159de93b954ee5b2f5d6810d056ab76983a76
|
data/.standard.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
email_forward_parser (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
json (2.6.3)
|
11
|
+
language_server-protocol (3.17.0.3)
|
12
|
+
lint_roller (1.0.0)
|
13
|
+
minitest (5.18.1)
|
14
|
+
parallel (1.23.0)
|
15
|
+
parser (3.2.2.3)
|
16
|
+
ast (~> 2.4.1)
|
17
|
+
racc
|
18
|
+
racc (1.7.1)
|
19
|
+
rainbow (3.1.1)
|
20
|
+
rake (13.0.6)
|
21
|
+
regexp_parser (2.8.1)
|
22
|
+
rexml (3.2.5)
|
23
|
+
rubocop (1.52.1)
|
24
|
+
json (~> 2.3)
|
25
|
+
parallel (~> 1.10)
|
26
|
+
parser (>= 3.2.2.3)
|
27
|
+
rainbow (>= 2.2.2, < 4.0)
|
28
|
+
regexp_parser (>= 1.8, < 3.0)
|
29
|
+
rexml (>= 3.2.5, < 4.0)
|
30
|
+
rubocop-ast (>= 1.28.0, < 2.0)
|
31
|
+
ruby-progressbar (~> 1.7)
|
32
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
33
|
+
rubocop-ast (1.29.0)
|
34
|
+
parser (>= 3.2.1.0)
|
35
|
+
rubocop-performance (1.18.0)
|
36
|
+
rubocop (>= 1.7.0, < 2.0)
|
37
|
+
rubocop-ast (>= 0.4.0)
|
38
|
+
ruby-progressbar (1.13.0)
|
39
|
+
standard (1.29.0)
|
40
|
+
language_server-protocol (~> 3.17.0.2)
|
41
|
+
lint_roller (~> 1.0)
|
42
|
+
rubocop (~> 1.52.0)
|
43
|
+
standard-custom (~> 1.0.0)
|
44
|
+
standard-performance (~> 1.1.0)
|
45
|
+
standard-custom (1.0.1)
|
46
|
+
lint_roller (~> 1.0)
|
47
|
+
standard-performance (1.1.0)
|
48
|
+
lint_roller (~> 1.0)
|
49
|
+
rubocop-performance (~> 1.18.0)
|
50
|
+
unicode-display_width (2.4.2)
|
51
|
+
|
52
|
+
PLATFORMS
|
53
|
+
arm64-darwin-22
|
54
|
+
|
55
|
+
DEPENDENCIES
|
56
|
+
email_forward_parser!
|
57
|
+
minitest (~> 5.0)
|
58
|
+
rake (~> 13.0)
|
59
|
+
standard (~> 1.3)
|
60
|
+
|
61
|
+
BUNDLED WITH
|
62
|
+
2.4.13
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.libs << "lib"
|
9
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
10
|
+
end
|
11
|
+
|
12
|
+
require "standard/rake"
|
13
|
+
|
14
|
+
task default: %i[test standard]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/email_forward_parser/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "email_forward_parser"
|
7
|
+
spec.version = EmailForwardParser::VERSION
|
8
|
+
spec.authors = ["Sean Collins"]
|
9
|
+
spec.email = ["dev@buildr.com"]
|
10
|
+
|
11
|
+
spec.summary = "Parse forwarded emails from body and subject"
|
12
|
+
spec.homepage = "https://github.com/buildrtech/email_forward_parser"
|
13
|
+
spec.license = "Nonstandard"
|
14
|
+
spec.required_ruby_version = ">= 3.2.2"
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(__dir__) do
|
19
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .github .tool-versions])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
# Uncomment to register a new dependency of your gem
|
29
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
30
|
+
|
31
|
+
# For more information and examples about making a new gem, check out our
|
32
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
33
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module EmailForwardParser
|
2
|
+
class MailboxParser
|
3
|
+
def initialize(regexes:, text:)
|
4
|
+
@regexes = regexes
|
5
|
+
@text = text
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
match = Utils.match_regexes(regexes, text)
|
10
|
+
|
11
|
+
if match && match.length > 0
|
12
|
+
mailboxes_line = match[match.length - 1].strip
|
13
|
+
|
14
|
+
if mailboxes_line
|
15
|
+
mailboxes = []
|
16
|
+
|
17
|
+
until mailboxes_line.empty?
|
18
|
+
mailbox_match = Utils.match_regexes(Regexes::MAILBOX, mailboxes_line)
|
19
|
+
|
20
|
+
# Address and/or name available?
|
21
|
+
if mailbox_match && mailbox_match.length > 0
|
22
|
+
address = nil
|
23
|
+
name = nil
|
24
|
+
|
25
|
+
# Address and name available?
|
26
|
+
if mailbox_match.length == 3
|
27
|
+
address = mailbox_match[2].strip
|
28
|
+
name = mailbox_match[1].strip
|
29
|
+
else
|
30
|
+
address = mailbox_match[1]&.strip
|
31
|
+
end
|
32
|
+
|
33
|
+
cleaned_name = if name&.empty?
|
34
|
+
nil
|
35
|
+
else
|
36
|
+
name
|
37
|
+
end
|
38
|
+
|
39
|
+
mailboxes.push({
|
40
|
+
address:,
|
41
|
+
|
42
|
+
# Some clients fill the name with the address \
|
43
|
+
# ("bessie.berry@acme.com <bessie.berry@acme.com>")
|
44
|
+
name: (address != cleaned_name) ? cleaned_name : nil
|
45
|
+
})
|
46
|
+
|
47
|
+
# Remove matched mailbox from mailboxes line
|
48
|
+
mailboxes_line = mailboxes_line.sub(mailbox_match[0], "").strip
|
49
|
+
|
50
|
+
if mailboxes_line
|
51
|
+
# Remove leading mailboxes separator \
|
52
|
+
# (", Nicholas <nicholas@globex.corp>")
|
53
|
+
Regexes::MAILBOXES_SEPARATORS.each do |separator|
|
54
|
+
if mailboxes_line[0] == separator
|
55
|
+
mailboxes_line = mailboxes_line[1..].strip
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
else
|
61
|
+
mailboxes.push({
|
62
|
+
address: mailboxes_line.strip,
|
63
|
+
name: nil
|
64
|
+
})
|
65
|
+
|
66
|
+
# No more matches
|
67
|
+
mailboxes_line = ""
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
return mailboxes
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
[]
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
attr_reader :regexes, :text
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require_relative "./regexes"
|
2
|
+
require_relative "./utils"
|
3
|
+
require_relative "./mailbox_parser"
|
4
|
+
|
5
|
+
module EmailForwardParser
|
6
|
+
class OriginalEmailParser
|
7
|
+
def initialize(text, body)
|
8
|
+
# Remove Byte Order Mark
|
9
|
+
text.gsub!(Regexes::BYTE_ORDER_MARK, "")
|
10
|
+
|
11
|
+
# Remove ">" at the beginning of each line, while keeping line breaks
|
12
|
+
text.gsub!(Regexes::QUOTE_LINE_BREAK, "")
|
13
|
+
|
14
|
+
# Remove ">" at the beginning of other lines
|
15
|
+
text.gsub!(Regexes::QUOTE, "")
|
16
|
+
|
17
|
+
# Remove " " at the beginning of lines
|
18
|
+
text.gsub!(Regexes::FOUR_SPACES, "")
|
19
|
+
|
20
|
+
@text = text
|
21
|
+
@body = body
|
22
|
+
end
|
23
|
+
|
24
|
+
def call
|
25
|
+
{
|
26
|
+
body: parse_original_body,
|
27
|
+
from: parse_original_from,
|
28
|
+
to: parse_original_to,
|
29
|
+
cc: parse_original_cc,
|
30
|
+
subject: parse_original_subject,
|
31
|
+
date: parse_original_date
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :text, :body
|
38
|
+
|
39
|
+
def parse_original_body
|
40
|
+
match = nil
|
41
|
+
|
42
|
+
# First method: extract the text after the Cc, To or Reply-To part \
|
43
|
+
# (Apple Mail, Gmail) or after the Subject part (Outlook Live)
|
44
|
+
regexes = [
|
45
|
+
Regexes::ORIGINAL_SUBJECT,
|
46
|
+
Regexes::ORIGINAL_CC,
|
47
|
+
Regexes::ORIGINAL_TO,
|
48
|
+
Regexes::ORIGINAL_REPLY_TO
|
49
|
+
]
|
50
|
+
|
51
|
+
regexes.each do |regex|
|
52
|
+
match = Utils.split_regexes(regex, text)
|
53
|
+
|
54
|
+
# A new line must be present between the Cc, To, Reply-To or Subject \
|
55
|
+
# part and the actual body
|
56
|
+
return match[2].strip if match && match.length == 3 && match[2].start_with?("\n\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Second method: extract the text after the Subject part \
|
60
|
+
# (New Outlook 2019, Yahoo Mail)
|
61
|
+
match = Utils.split_regexes(
|
62
|
+
Regexes::ORIGINAL_SUBJECT + Regexes::ORIGINAL_SUBJECT_LAX,
|
63
|
+
text
|
64
|
+
)
|
65
|
+
|
66
|
+
# No new line must be present between the Subject part and the actual body
|
67
|
+
return match[2].strip if match && match.length == 3
|
68
|
+
|
69
|
+
# Third method: return the raw text, as there is no original information \
|
70
|
+
# embedded (no Cc, To, Subject, etc.) (Outlook 2019)
|
71
|
+
text
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_mailbox(regexes, text)
|
75
|
+
MailboxParser.new(regexes:, text:).call
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_original_from
|
79
|
+
address = nil
|
80
|
+
name = nil
|
81
|
+
|
82
|
+
# First method: extract the author via the From part (Apple Mail, Gmail,
|
83
|
+
# Outlook Live, New Outlook 2019, Thunderbird)
|
84
|
+
author = parse_mailbox(Regexes::ORIGINAL_FROM, text)
|
85
|
+
|
86
|
+
# Author found?
|
87
|
+
return author.first if author.any? && author.first[:address] && !author.first[:address].empty?
|
88
|
+
|
89
|
+
# Second method: extract the author via the separator (Outlook 2019)
|
90
|
+
match = Utils.match_regexes(Regexes::SEPARATOR, body)
|
91
|
+
|
92
|
+
if match && match.length == 4 && match.named_captures
|
93
|
+
# Notice: the order of parts may change depending on the localization,
|
94
|
+
# hence the use of named groups
|
95
|
+
address = match.named_captures["from_address"].strip
|
96
|
+
name = match.named_captures["from_name"].strip
|
97
|
+
|
98
|
+
return {
|
99
|
+
address:,
|
100
|
+
|
101
|
+
# Some clients fill the name with the address
|
102
|
+
# ("bessie.berry@acme.com <bessie.berry@acme.com>")
|
103
|
+
name: (address != name) ? name : nil
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
# Third method: extract the author via the From part, using lax regexes
|
108
|
+
# (Yahoo Mail)
|
109
|
+
match = Utils.match_regexes(Regexes::ORIGINAL_FROM_LAX, text)
|
110
|
+
|
111
|
+
if match && match.length > 1
|
112
|
+
address = match[3].strip
|
113
|
+
name = match[2].strip
|
114
|
+
|
115
|
+
return {
|
116
|
+
address:,
|
117
|
+
|
118
|
+
# Some clients fill the name with the address
|
119
|
+
# ("bessie.berry@acme.com <bessie.berry@acme.com>")
|
120
|
+
name: (address != name) ? name : nil
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
{
|
125
|
+
address:,
|
126
|
+
name:
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def parse_original_to
|
131
|
+
# First method: extract the primary recipient(s) via the To part
|
132
|
+
# (Apple Mail, Gmail, Outlook Live, New Outlook 2019, Thunderbird)
|
133
|
+
recipients = parse_mailbox(
|
134
|
+
Regexes::ORIGINAL_TO,
|
135
|
+
text
|
136
|
+
)
|
137
|
+
|
138
|
+
# Recipient(s) found?
|
139
|
+
return recipients if recipients.any?
|
140
|
+
|
141
|
+
# Second method: the Subject, Date, and Cc parts are stuck to the To part,
|
142
|
+
# remove them before attempting a new extract, using lax regexes (Yahoo Mail)
|
143
|
+
clean_text = Utils.replace_regexes(Regexes::ORIGINAL_SUBJECT_LAX, text)
|
144
|
+
|
145
|
+
clean_text = Utils.replace_regexes(Regexes::ORIGINAL_DATE_LAX, clean_text)
|
146
|
+
|
147
|
+
clean_text = Utils.replace_regexes(Regexes::ORIGINAL_CC_LAX, clean_text)
|
148
|
+
|
149
|
+
parse_mailbox(
|
150
|
+
Regexes::ORIGINAL_TO_LAX,
|
151
|
+
clean_text
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
def parse_original_cc
|
156
|
+
# First method: extract the carbon-copy recipient(s) via the Cc part
|
157
|
+
# (Apple Mail, Gmail, Outlook Live, New Outlook 2019, Thunderbird)
|
158
|
+
recipients = parse_mailbox(
|
159
|
+
Regexes::ORIGINAL_CC,
|
160
|
+
text
|
161
|
+
)
|
162
|
+
|
163
|
+
# Recipient(s) found?
|
164
|
+
return recipients if recipients.any?
|
165
|
+
|
166
|
+
# Second method: the Subject and Date parts are stuck to the To part,
|
167
|
+
# remove them before attempting a new extract, using lax regexes (Yahoo Mail)
|
168
|
+
clean_text = Utils.replace_regexes(Regexes::ORIGINAL_SUBJECT_LAX, text)
|
169
|
+
|
170
|
+
clean_text = Utils.replace_regexes(Regexes::ORIGINAL_DATE_LAX, clean_text)
|
171
|
+
|
172
|
+
parse_mailbox(
|
173
|
+
Regexes::ORIGINAL_CC_LAX,
|
174
|
+
clean_text
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
def parse_original_subject
|
179
|
+
# First method: extract the subject via the Subject part
|
180
|
+
# (Apple Mail, Gmail, Outlook Live, New Outlook 2019, Thunderbird)
|
181
|
+
match = Utils.match_regexes(Regexes::ORIGINAL_SUBJECT, text)
|
182
|
+
|
183
|
+
return match[1].strip if match && match.length > 0
|
184
|
+
|
185
|
+
# Second method: extract the subject via the Subject part, using lax regexes (Yahoo Mail)
|
186
|
+
match = Utils.match_regexes(Regexes::ORIGINAL_SUBJECT_LAX, text)
|
187
|
+
|
188
|
+
return unless match && match.length > 0
|
189
|
+
|
190
|
+
match[1].strip
|
191
|
+
end
|
192
|
+
|
193
|
+
def parse_original_date
|
194
|
+
# First method: extract the date via the Date part
|
195
|
+
# (Apple Mail, Gmail, Outlook Live, New Outlook 2019, Thunderbird)
|
196
|
+
match = Utils.match_regexes(Regexes::ORIGINAL_DATE, text)
|
197
|
+
|
198
|
+
return match[1].strip if match && match.length > 0
|
199
|
+
|
200
|
+
# Second method: extract the date via the separator (Outlook 2019)
|
201
|
+
match = Utils.match_regexes(Regexes::SEPARATOR, body)
|
202
|
+
|
203
|
+
if match && match.length == 4 && match.named_captures.any?
|
204
|
+
# Notice: the order of parts may change depending on the localization,
|
205
|
+
# hence the use of named groups
|
206
|
+
return match.named_captures["date"].strip
|
207
|
+
end
|
208
|
+
|
209
|
+
# Third method: the Subject part is stuck to the Date part, remove it
|
210
|
+
# before attempting a new extract, using lax regexes (Yahoo Mail)
|
211
|
+
clean_text = Utils.replace_regexes(
|
212
|
+
Regexes::ORIGINAL_SUBJECT_LAX,
|
213
|
+
text
|
214
|
+
)
|
215
|
+
|
216
|
+
match = Utils.match_regexes(Regexes::ORIGINAL_DATE_LAX, clean_text)
|
217
|
+
|
218
|
+
return unless match && match.length > 0
|
219
|
+
|
220
|
+
match[1].strip
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative "./regexes"
|
2
|
+
require_relative "./utils"
|
3
|
+
|
4
|
+
module EmailForwardParser
|
5
|
+
class Parser
|
6
|
+
def parse_subject(subject)
|
7
|
+
match = Utils.match_regexes(Regexes::SUBJECT, subject)
|
8
|
+
|
9
|
+
# Notice: return an empty string if the detected subject is empty
|
10
|
+
# (e.g. 'Fwd: ')
|
11
|
+
match[1].strip || "" if match && match.length > 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_body(body, forwarded:)
|
15
|
+
# Replace carriage return by regular line break
|
16
|
+
body.gsub!(/#{Regexes::CARRIAGE_RETURN}/o, "\n")
|
17
|
+
|
18
|
+
# Remove Byte Order Mark
|
19
|
+
body.gsub!(/#{Regexes::BYTE_ORDER_MARK}/o, "")
|
20
|
+
|
21
|
+
# First method: split via the separator (Apple Mail, Gmail, Outlook Live,
|
22
|
+
# Outlook 2019, Yahoo Mail, Thunderbird)
|
23
|
+
match = Utils.split_regexes(Regexes::SEPARATOR, body)
|
24
|
+
|
25
|
+
if match && match.length > 1
|
26
|
+
return {
|
27
|
+
body:,
|
28
|
+
message: match[0].strip,
|
29
|
+
email: match[-1].strip
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Attempt second method?
|
34
|
+
# Notice: as this second method is more uncertain (we split via the From
|
35
|
+
# part, without further verification), we have to be sure we can
|
36
|
+
# attempt it. The `forwarded` boolean gives the confirmation that the
|
37
|
+
# email was indeed forwarded (detected from the Subject part)
|
38
|
+
if forwarded
|
39
|
+
# Second method: split via the Form part (New Outlook 2019)
|
40
|
+
match = Utils.split_regexes(Regexes::ORIGINAL_FROM, body)
|
41
|
+
|
42
|
+
if match && match.length > 3
|
43
|
+
# The From has been detached by `split`, attach it back
|
44
|
+
email = match[1] + match[match.length - 1]
|
45
|
+
|
46
|
+
return {
|
47
|
+
body:,
|
48
|
+
message: match[0].strip,
|
49
|
+
email: email.strip
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
{}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
module EmailForwardParser
|
2
|
+
module Regexes
|
3
|
+
QUOTE_LINE_BREAK = /^(>+)\s?$/m # Apple Mail
|
4
|
+
QUOTE = /^(>+)\s?/m # Apple Mail
|
5
|
+
FOUR_SPACES = /^(\ {4})\s?/m # Outlook 2019
|
6
|
+
CARRIAGE_RETURN = /\r\n/m # Outlook 2019
|
7
|
+
BYTE_ORDER_MARK = /\uFEFF/m # Outlook 2019
|
8
|
+
SEPARATOR = [
|
9
|
+
/^>?\s*Begin forwarded message\s?:/m, # Apple Mail (en)
|
10
|
+
/^>?\s*Začátek přeposílané zprávy\s?:/m, # Apple Mail (cs)
|
11
|
+
/^>?\s*Start på videresendt besked\s?:/m, # Apple Mail (da)
|
12
|
+
/^>?\s*Anfang der weitergeleiteten Nachricht\s?:/m, # Apple Mail (de)
|
13
|
+
/^>?\s*Inicio del mensaje reenviado\s?:/m, # Apple Mail (es)
|
14
|
+
/^>?\s*Välitetty viesti alkaa\s?:/m, # Apple Mail (fi)
|
15
|
+
/^>?\s*Début du message réexpédié\s?:/m, # Apple Mail (fr)
|
16
|
+
/^>?\s*Début du message transféré\s?:/m, # Apple Mail iOS (fr)
|
17
|
+
/^>?\s*Započni proslijeđenu poruku\s?:/m, # Apple Mail (hr)
|
18
|
+
/^>?\s*Továbbított levél kezdete\s?:/m, # Apple Mail (hu)
|
19
|
+
/^>?\s*Inizio messaggio inoltrato\s?:/m, # Apple Mail (it)
|
20
|
+
/^>?\s*Begin doorgestuurd bericht\s?:/m, # Apple Mail (nl)
|
21
|
+
/^>?\s*Videresendt melding\s?:/m, # Apple Mail (no)
|
22
|
+
/^>?\s*Początek przekazywanej wiadomości\s?:/m, # Apple Mail (pl)
|
23
|
+
/^>?\s*Início da mensagem reencaminhada\s?:/m, # Apple Mail (pt)
|
24
|
+
/^>?\s*Início da mensagem encaminhada\s?:/m, # Apple Mail (pt-br)
|
25
|
+
/^>?\s*Începe mesajul redirecționat\s?:/m, # Apple Mail (ro)
|
26
|
+
/^>?\s*Начало переадресованного сообщения\s?:/m, # Apple Mail (ro)
|
27
|
+
/^>?\s*Začiatok preposlanej správy\s?:/m, # Apple Mail (sk)
|
28
|
+
/^>?\s*Vidarebefordrat mejl\s?:/m, # Apple Mail (sv)
|
29
|
+
/^>?\s*İleti başlangıcı\s?:/m, # Apple Mail (tr)
|
30
|
+
/^>?\s*Початок листа, що пересилається\s?:/m, # Apple Mail (uk)
|
31
|
+
/^\s*-{8,10}\s*Forwarded message\s*-{8,10}\s*/m, # Gmail (all locales)
|
32
|
+
/^\s*_{32}\s*$/m, # Outlook Live (all locales)
|
33
|
+
/^\s?Dne\s?(?<date>.+),\s?(?<from_name>.+)\s*[\[|<](?<from_address>.+)[\]|>]\s?napsal\(a\)\s?:/m, # Outlook 2019 (cz)
|
34
|
+
/^\s?D.\s?(?<date>.+)\s?skrev\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?:/m, # Outlook 2019 (da)
|
35
|
+
/^\s?Am\s?(?<date>.+)\s?schrieb\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?:/m, # Outlook 2019 (de)
|
36
|
+
/^\s?On\s?(?<date>.+),\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?wrote\s?:/m, # Outlook 2019 (en)
|
37
|
+
/^\s?El\s?(?<date>.+),\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?escribió\s?:/m, # Outlook 2019 (es)
|
38
|
+
/^\s?Le\s?(?<date>.+),\s?«(?<from_name>.+)»\s*[\[|<](?<from_address>.+)[\]|>]\s?a écrit\s?:/m, # Outlook 2019 (fr)
|
39
|
+
/^\s?(?<from_name>.+)\s*[\[|<](?<from_address>.+)[\]|>]\s?kirjoitti\s?(?<date>.+)\s?:/m, # Outlook 2019 (fi)
|
40
|
+
/^\s?(?<date>.+)\s?időpontban\s?(?<from_name>.+)\s*[\[|<(](?<from_address>.+)[\]|>)]\s?ezt írta\s?:/m, # Outlook 2019 (hu)
|
41
|
+
/^\s?Il giorno\s?(?<date>.+)\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?ha scritto\s?:/m, # Outlook 2019 (it)
|
42
|
+
/^\s?Op\s?(?<date>.+)\s?heeft\s?(?<from_name>.+)\s*[\[|<](?<from_address>.+)[\]|>]\s?geschreven\s?:/m, # Outlook 2019 (nl)
|
43
|
+
/^\s?(?<from_name>.+)\s*[\[|<](?<from_address>.+)[\]|>]\s?skrev følgende den\s?(?<date>.+)\s?:/m, # Outlook 2019 (no)
|
44
|
+
/^\s?Dnia\s?(?<date>.+)\s?„(?<from_name>.+)”\s*[\[|<](?<from_address>.+)[\]|>]\s?napisał\s?:/m, # Outlook 2019 (pl)
|
45
|
+
/^\s?Em\s?(?<date>.+),\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?escreveu\s?:/m, # Outlook 2019 (pt)
|
46
|
+
/^\s?(?<date>.+)\s?пользователь\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?написал\s?:/m, # Outlook 2019 (ru)
|
47
|
+
/^\s?(?<date>.+)\s?používateľ\s?(?<from_name>.+)\s*\([\[|<](?<from_address>.+)[\]|>]\)\s?napísal\s?:/m, # Outlook 2019 (sk)
|
48
|
+
/^\s?Den\s?(?<date>.+)\s?skrev\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>]\s?följande\s?:/m, # Outlook 2019 (sv)
|
49
|
+
/^\s?"(?<from_name>.+)"\s*[\[|<](?<from_address>.+)[\]|>],\s?(?<date>.+)\s?tarihinde şunu yazdı\s?:/m, # Outlook 2019 (tr)
|
50
|
+
/\s*-{5,8} Přeposlaná zpráva -{5,8}\s*/m, # Yahoo Mail (cs), Thunderbird (cs)
|
51
|
+
/\s*-{5,8} Videresendt meddelelse -{5,8}\s*/m, # Yahoo Mail (da), Thunderbird (da)
|
52
|
+
/\s*-{5,8} Weitergeleitete Nachricht -{5,8}\s*/m, # Yahoo Mail (de), Thunderbird (de)
|
53
|
+
/\s*-{5,8} Forwarded Message -{5,8}\s*/m, # Yahoo Mail (en), Thunderbird (en)
|
54
|
+
/\s*-{5,8} Mensaje reenviado -{5,8}\s*/m, # Yahoo Mail (es), Thunderbird (es)
|
55
|
+
/\s*-{5} Edelleenlähetetty viesti -{5}\s*/m, # Yahoo Mail (fi)
|
56
|
+
/\s*-{5} Message transmis -{5}\s*/m, # Yahoo Mail (fr)
|
57
|
+
/\s*-{5,8} Továbbított üzenet -{5,8}\s*/m, # Yahoo Mail (hu), Thunderbird (hu)
|
58
|
+
/\s*-{5} Messaggio inoltrato -{5}\s*/m, # Yahoo Mail (it)
|
59
|
+
/\s*-{5,8} Doorgestuurd bericht -{5,8}\s*/m, # Yahoo Mail (nl), Thunderbird (nl)
|
60
|
+
/\s*-{5,8} Videresendt melding -{5,8}\s*/m, # Yahoo Mail (no), Thunderbird (no)
|
61
|
+
/\s*-{5} Przekazana wiadomość -{5}\s*/m, # Yahoo Mail (pl)
|
62
|
+
/\s*-{5,8} Mensagem reencaminhada -{5,8}\s*/m, # Yahoo Mail (pt), Thunderbird (pt)
|
63
|
+
/\s*-{5,8} Mensagem encaminhada -{5,8}\s*/m, # Yahoo Mail (pt-br), Thunderbird (pt-br)
|
64
|
+
/\s*-{5,8} Mesaj redirecționat -{5,8}\s*/m, # Yahoo Mail (ro)
|
65
|
+
/\s*-{5} Пересылаемое сообщение -{5}\s*/m, # Yahoo Mail (ru)
|
66
|
+
/\s*-{5} Preposlaná správa -{5}\s*/m, # Yahoo Mail (sk)
|
67
|
+
/\s*-{5,8} Vidarebefordrat meddelande -{5,8}\s*/m, # Yahoo Mail (sv), Thunderbird (sv)
|
68
|
+
/\s*-{5} İletilmiş Mesaj -{5}\s*/m, # Yahoo Mail (tr)
|
69
|
+
/\s*-{5} Перенаправлене повідомлення -{5}\s*/m, # Yahoo Mail (uk)
|
70
|
+
%r{\s*-{8} Välitetty viesti / Fwd.Msg -{8}\s*}m, # Thunderbird (fi)
|
71
|
+
/\s*-{8} Message transféré -{8}\s*/m, # Thunderbird (fr)
|
72
|
+
/\s*-{8} Proslijeđena poruka -{8}\s*/m, # Thunderbird (hr)
|
73
|
+
/\s*-{8} Messaggio Inoltrato -{8}\s*/m, # Thunderbird (it)
|
74
|
+
/\s*-{3} Treść przekazanej wiadomości -{3}\s*/m, # Thunderbird (pl)
|
75
|
+
/\s*-{8} Перенаправленное сообщение -{8}\s*/m, # Thunderbird (ru)
|
76
|
+
/\s*-{8} Preposlaná správa --- Forwarded Message -{8}\s*/m, # Thunderbird (sk)
|
77
|
+
/\s*-{8} İletilen İleti -{8}\s*/m, # Thunderbird (tr)
|
78
|
+
/\s*-{8} Переслане повідомлення -{8}\s*/m # Thunderbird (uk)
|
79
|
+
].freeze
|
80
|
+
|
81
|
+
SUBJECT = [
|
82
|
+
/^Fw:(.*)/, # Outlook Live (cs, en, hr, hu, sk), Yahoo Mail (all locales)
|
83
|
+
/^VS:(.*)/, # Outlook Live (da), New Outlook 2019 (da)
|
84
|
+
/^WG:(.*)/, # Outlook Live (de), New Outlook 2019 (de)
|
85
|
+
/^RV:(.*)/, # Outlook Live (es), New Outlook 2019 (es)
|
86
|
+
/^TR:(.*)/, # Outlook Live (fr), New Outlook 2019 (fr)
|
87
|
+
/^I:(.*)/, # Outlook Live (it), New Outlook 2019 (it)
|
88
|
+
/^FW:(.*)/, # Outlook Live (nl, pt), New Outlook 2019 (cs, en, hu, nl, pt, ru, sk), Outlook 2019 (all locales)
|
89
|
+
/^Vs:(.*)/, # Outlook Live (no)
|
90
|
+
/^PD:(.*)/, # Outlook Live (pl), New Outlook 2019 (pl)
|
91
|
+
/^ENC:(.*)/, # Outlook Live (pt-br), New Outlook 2019 (pt-br)
|
92
|
+
/^Redir.:(.*)/, # Outlook Live (ro)
|
93
|
+
/^VB:(.*)/, # Outlook Live (sv), New Outlook 2019 (sv)
|
94
|
+
/^VL:(.*)/, # New Outlook 2019 (fi)
|
95
|
+
/^Videresend:(.*)/, # New Outlook 2019 (no)
|
96
|
+
/^İLT:(.*)/, # New Outlook 2019 (tr)
|
97
|
+
/^Fwd:(.*)/ # Gmail (all locales), Thunderbird (all locales)
|
98
|
+
].freeze
|
99
|
+
|
100
|
+
ORIGINAL_FROM = [
|
101
|
+
/^(\s*From\s?:(.+))$/, # Apple Mail (en), Outlook Live (all locales), New Outlook 2019 (en), Thunderbird (da, en)
|
102
|
+
/^(\s*Od\s?:(.+))$/, # Apple Mail (cs, pl, sk), Gmail (cs, pl, sk), New Outlook 2019 (cs, pl, sk), Thunderbird (cs, sk)
|
103
|
+
/^(\s*Fra\s?:(.+))$/, # Apple Mail (da, no), Gmail (da, no), New Outlook 2019 (da), Thunderbird (no)
|
104
|
+
/^(\s*Von\s?:(.+))$/, # Apple Mail (de), Gmail (de), New Outlook 2019 (de), Thunderbird (de)
|
105
|
+
/^(\s*De\s?:(.+))$/, # Apple Mail (es, fr, pt, pt-br), Gmail (es, fr, pt, pt-br), New Outlook 2019 (es, fr, pt, pt-br), Thunderbird (fr, pt, pt-br)
|
106
|
+
/^(\s*Lähettäjä\s?:(.+))$/, # Apple Mail (fi), Gmail (fi), New Outlook 2019 (fi), Thunderbird (fi)
|
107
|
+
/^(\s*Šalje\s?:(.+))$/, # Apple Mail (hr), Gmail (hr), Thunderbird (hr)
|
108
|
+
/^(\s*Feladó\s?:(.+))$/, # Apple Mail (hu), Gmail (hu), New Outlook 2019 (fr), Thunderbird (hu)
|
109
|
+
/^(\s*Da\s?:(.+))$/, # Apple Mail (it), Gmail (it), New Outlook 2019 (it)
|
110
|
+
/^(\s*Van\s?:(.+))$/, # Apple Mail (nl), Gmail (nl), New Outlook 2019 (nl), Thunderbird (nl)
|
111
|
+
/^(\s*Expeditorul\s?:(.+))$/, # Apple Mail (ro)
|
112
|
+
/^(\s*Отправитель\s?:(.+))$/, # Apple Mail (ru)
|
113
|
+
/^(\s*Från\s?:(.+))$/, # Apple Mail (sv), Gmail (sv), New Outlook 2019 (sv), Thunderbird (sv)
|
114
|
+
/^(\s*Kimden\s?:(.+))$/, # Apple Mail (tr), Thunderbird (tr)
|
115
|
+
/^(\s*Від кого\s?:(.+))$/, # Apple Mail (uk)
|
116
|
+
/^(\s*Saatja\s?:(.+))$/, # Gmail (et)
|
117
|
+
/^(\s*De la\s?:(.+))$/, # Gmail (ro)
|
118
|
+
/^(\s*Gönderen\s?:(.+))$/, # Gmail (tr)
|
119
|
+
/^(\s*От\s?:(.+))$/, # Gmail (ru), New Outlook 2019 (ru), Thunderbird (ru)
|
120
|
+
/^(\s*Від\s?:(.+))$/, # Gmail (uk), Thunderbird (uk)
|
121
|
+
/^(\s*Mittente\s?:(.+))$/, # Thunderbird (it)
|
122
|
+
/^(\s*Nadawca\s?:(.+))$/, # Thunderbird (pl)
|
123
|
+
/^(\s*de la\s?:(.+))$/ # Thunderbird (ro)
|
124
|
+
].freeze
|
125
|
+
|
126
|
+
ORIGINAL_FROM_LAX = [
|
127
|
+
/(\s*From\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (en)
|
128
|
+
/(\s*Od\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (cs, pl, sk)
|
129
|
+
/(\s*Fra\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (da, no)
|
130
|
+
/(\s*Von\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (de)
|
131
|
+
/(\s*De\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (es, fr, pt, pt-br)
|
132
|
+
/(\s*Lähettäjä\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (fi)
|
133
|
+
/(\s*Feladó\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (hu)
|
134
|
+
/(\s*Da\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (it)
|
135
|
+
/(\s*Van\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (nl)
|
136
|
+
/(\s*De la\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (ro)
|
137
|
+
/(\s*От\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (ru)
|
138
|
+
/(\s*Från\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (sv)
|
139
|
+
/(\s*Kimden\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/, # Yahoo Mail (tr)
|
140
|
+
/(\s*Від\s?:(.+?)\s?\n?\s*[\[|<](.+?)[\]|>])/ # Yahoo Mail (uk)
|
141
|
+
].freeze
|
142
|
+
|
143
|
+
ORIGINAL_SUBJECT = [
|
144
|
+
/^Subject\s?:(.+)/i, # Apple Mail (en), Gmail (all locales), Outlook Live (all locales), New Outlook 2019 (en), Thunderbird (da, en)
|
145
|
+
/^Předmět\s?:(.+)/i, # Apple Mail (cs), New Outlook 2019 (cs), Thunderbird (cs)
|
146
|
+
/^Emne\s?:(.+)/i, # Apple Mail (da, no), New Outlook 2019 (da), Thunderbird (no)
|
147
|
+
/^Betreff\s?:(.+)/i, # Apple Mail (de), New Outlook 2019 (de), Thunderbird (de)
|
148
|
+
/^Asunto\s?:(.+)/i, # Apple Mail (es), New Outlook 2019 (es), Thunderbird (es)
|
149
|
+
/^Aihe\s?:(.+)/i, # Apple Mail (fi), New Outlook 2019 (fi), Thunderbird (fi)
|
150
|
+
/^Objet\s?:(.+)/i, # Apple Mail (fr), New Outlook 2019 (fr)
|
151
|
+
/^Predmet\s?:(.+)/i, # Apple Mail (hr, sk), New Outlook 2019 (sk), Thunderbird (sk)
|
152
|
+
/^Tárgy\s?:(.+)/i, # Apple Mail (hu), New Outlook 2019 (hu), Thunderbird (hu)
|
153
|
+
/^Oggetto\s?:(.+)/i, # Apple Mail (it), New Outlook 2019 (it), Thunderbird (it)
|
154
|
+
/^Onderwerp\s?:(.+)/i, # Apple Mail (nl), New Outlook 2019 (nl), Thunderbird (nl)
|
155
|
+
/^Temat\s?:(.+)/i, # Apple Mail (pl), New Outlook 2019 (pl), Thunderbird (pl)
|
156
|
+
/^Assunto\s?:(.+)/i, # Apple Mail (pt, pt-br), New Outlook 2019 (pt, pt-br), Thunderbird (pt, pt-br)
|
157
|
+
/^Subiectul\s?:(.+)/i, # Apple Mail (ro), Thunderbird (ro)
|
158
|
+
/^Тема\s?:(.+)/i, # Apple Mail (ru, uk), New Outlook 2019 (ru), Thunderbird (ru, uk)
|
159
|
+
/^Ämne\s?:(.+)/i, # Apple Mail (sv), New Outlook 2019 (sv), Thunderbird (sv)
|
160
|
+
/^Konu\s?:(.+)/i, # Apple Mail (tr), Thunderbird (tr)
|
161
|
+
/^Sujet\s?:(.+)/i, # Thunderbird (fr)
|
162
|
+
/^Naslov\s?:(.+)/i # Thunderbird (hr)
|
163
|
+
].freeze
|
164
|
+
|
165
|
+
ORIGINAL_SUBJECT_LAX = [
|
166
|
+
/Subject\s?:(.+)/i, # Yahoo Mail (en)
|
167
|
+
/Emne\s?:(.+)/i, # Yahoo Mail (da, no)
|
168
|
+
/Předmět\s?:(.+)/i, # Yahoo Mail (cs)
|
169
|
+
/Betreff\s?:(.+)/i, # Yahoo Mail (de)
|
170
|
+
/Asunto\s?:(.+)/i, # Yahoo Mail (es)
|
171
|
+
/Aihe\s?:(.+)/i, # Yahoo Mail (fi)
|
172
|
+
/Objet\s?:(.+)/i, # Yahoo Mail (fr)
|
173
|
+
/Tárgy\s?:(.+)/i, # Yahoo Mail (hu)
|
174
|
+
/Oggetto\s?:(.+)/i, # Yahoo Mail (it)
|
175
|
+
/Onderwerp\s?:(.+)/i, # Yahoo Mail (nl)
|
176
|
+
/Assunto\s?:?(.+)/i, # Yahoo Mail (pt, pt-br)
|
177
|
+
/Temat\s?:(.+)/i, # Yahoo Mail (pl)
|
178
|
+
/Subiect\s?:(.+)/i, # Yahoo Mail (ro)
|
179
|
+
/Тема\s?:(.+)/i, # Yahoo Mail (ru, uk)
|
180
|
+
/Predmet\s?:(.+)/i, # Yahoo Mail (sk)
|
181
|
+
/Ämne\s?:(.+)/i, # Yahoo Mail (sv)
|
182
|
+
/Konu\s?:(.+)/i # Yahoo Mail (tr)
|
183
|
+
].freeze
|
184
|
+
|
185
|
+
ORIGINAL_TO = [
|
186
|
+
/^\s*To\s?:(.+)$/, # Apple Mail (en), Gmail (all locales), Outlook Live (all locales), Thunderbird (da, en)
|
187
|
+
/^\s*Komu\s?:(.+)$/, # Apple Mail (cs), New Outlook 2019 (cs, sk), Thunderbird (cs)
|
188
|
+
/^\s*Til\s?:(.+)$/, # Apple Mail (da, no), New Outlook 2019 (da), Thunderbird (no)
|
189
|
+
/^\s*An\s?:(.+)$/, # Apple Mail (de), New Outlook 2019 (de), Thunderbird (de)
|
190
|
+
/^\s*Para\s?:(.+)$/, # Apple Mail (es, pt, pt-br), New Outlook 2019 (es, pt, pt-br), Thunderbird (es, pt, pt-br)
|
191
|
+
/^\s*Vastaanottaja\s?:(.+)$/, # Apple Mail (fi), New Outlook 2019 (fi), Thunderbird (fi)
|
192
|
+
/^\s*À\s?:(.+)$/, # Apple Mail (fr), New Outlook 2019 (fr)
|
193
|
+
/^\s*Prima\s?:(.+)$/, # Apple Mail (hr), Thunderbird (hr)
|
194
|
+
/^\s*Címzett\s?:(.+)$/, # Apple Mail (hu), New Outlook 2019 (hu), Thunderbird (hu)
|
195
|
+
/^\s*A\s?:(.+)$/, # Apple Mail (it), New Outlook 2019 (it), Thunderbird (it)
|
196
|
+
/^\s*Aan\s?:(.+)$/, # Apple Mail (nl), New Outlook 2019 (nl), Thunderbird (nl)
|
197
|
+
/^\s*Do\s?:(.+)$/, # Apple Mail (pl), New Outlook 2019 (pl)
|
198
|
+
/^\s*Destinatarul\s?:(.+)$/, # Apple Mail (ro)
|
199
|
+
/^\s*Кому\s?:(.+)$/, # Apple Mail (ru, uk), New Outlook 2019 (ru), Thunderbird (ru, uk)
|
200
|
+
/^\s*Pre\s?:(.+)$/, # Apple Mail (sk), Thunderbird (sk)
|
201
|
+
/^\s*Till\s?:(.+)$/, # Apple Mail (sv), New Outlook 2019 (sv), Thunderbird (sv)
|
202
|
+
/^\s*Kime\s?:(.+)$/, # Apple Mail (tr), Thunderbird (tr)
|
203
|
+
/^\s*Pour\s?:(.+)$/, # Thunderbird (fr)
|
204
|
+
/^\s*Adresat\s?:(.+)$/ # Thunderbird (pl)
|
205
|
+
].freeze
|
206
|
+
|
207
|
+
ORIGINAL_TO_LAX = [
|
208
|
+
/\s*To\s?:(.+)$/, # Yahoo Mail (en)
|
209
|
+
/\s*Komu\s?:(.+)$/, # Yahoo Mail (cs, sk)
|
210
|
+
/\s*Til\s?:(.+)$/, # Yahoo Mail (da, no, sv)
|
211
|
+
/\s*An\s?:(.+)$/, # Yahoo Mail (de)
|
212
|
+
/\s*Para\s?:(.+)$/, # Yahoo Mail (es, pt, pt-br)
|
213
|
+
/\s*Vastaanottaja\s?:(.+)$/, # Yahoo Mail (fi)
|
214
|
+
/\s*À\s?:(.+)$/, # Yahoo Mail (fr)
|
215
|
+
/\s*Címzett\s?:(.+)$/, # Yahoo Mail (hu)
|
216
|
+
/\s*A\s?:(.+)$/, # Yahoo Mail (it)
|
217
|
+
/\s*Aan\s?:(.+)$/, # Yahoo Mail (nl)
|
218
|
+
/\s*Do\s?:(.+)$/, # Yahoo Mail (pl)
|
219
|
+
/\s*Către\s?:(.+)$/, # Yahoo Mail (ro), Thunderbird (ro)
|
220
|
+
/\s*Кому\s?:(.+)$/, # Yahoo Mail (ru, uk)
|
221
|
+
/\s*Till\s?:(.+)$/, # Yahoo Mail (sv)
|
222
|
+
/\s*Kime\s?:(.+)$/ # Yahoo Mail (tr)
|
223
|
+
]
|
224
|
+
|
225
|
+
ORIGINAL_CC = [
|
226
|
+
/^\s*Cc\s?:(.+)$/, # Apple Mail (en, da, es, fr, hr, it, pt, pt-br, ro, sk), Gmail (all locales), Outlook Live (all locales), New Outlook 2019 (da, de, en, fr, it, pt-br)
|
227
|
+
/^\s*CC\s?:(.+)$/, # New Outlook 2019 (es, nl, pt), Thunderbird (da, en, es, fi, hr, hu, it, nl, no, pt, pt-br, ro, tr, uk)
|
228
|
+
/^\s*Kopie\s?:(.+)$/, # Apple Mail (cs, de, nl), New Outlook 2019 (cs), Thunderbird (cs)
|
229
|
+
/^\s*Kopio\s?:(.+)$/, # Apple Mail (fi), New Outlook 2019 (es)
|
230
|
+
/^\s*Másolat\s?:(.+)$/, # Apple Mail (hu)
|
231
|
+
/^\s*Kopi\s?:(.+)$/, # Apple Mail (no)
|
232
|
+
/^\s*Dw\s?:(.+)$/, # Apple Mail (pl)
|
233
|
+
/^\s*Копия\s?:(.+)$/, # Apple Mail (ru), New Outlook 2019 (ru), Thunderbird (ru)
|
234
|
+
/^\s*Kopia\s?:(.+)$/, # Apple Mail (sv), New Outlook 2019 (sv), Thunderbird (pl, sv)
|
235
|
+
/^\s*Bilgi\s?:(.+)$/, # Apple Mail (tr)
|
236
|
+
/^\s*Копія\s?:(.+)$/, # Apple Mail (uk),
|
237
|
+
/^\s*Másolatot kap\s?:(.+)$/, # New Outlook 2019 (hu)
|
238
|
+
/^\s*Kópia\s?:(.+)$/, # New Outlook 2019 (sk), Thunderbird (sk)
|
239
|
+
/^\s*DW\s?:(.+)$/, # New Outlook 2019 (pl)
|
240
|
+
/^\s*Kopie \(CC\)\s?:(.+)$/, # Thunderbird (de)
|
241
|
+
/^\s*Copie à\s?:(.+)$/ # Thunderbird (fr)
|
242
|
+
].freeze
|
243
|
+
|
244
|
+
ORIGINAL_CC_LAX = [
|
245
|
+
/\s*Cc\s?:(.+)$/, # Yahoo Mail (da, en, it, nl, pt, pt-br, ro, tr)
|
246
|
+
/\s*CC\s?:(.+)$/, # Yahoo Mail (de, es)
|
247
|
+
/\s*Kopie\s?:(.+)$/, # Yahoo Mail (cs)
|
248
|
+
/\s*Kopio\s?:(.+)$/, # Yahoo Mail (fi)
|
249
|
+
/\s*Másolat\s?:(.+)$/, # Yahoo Mail (hu)
|
250
|
+
/\s*Kopi\s?:(.+)$/, # Yahoo Mail (no)
|
251
|
+
/\s*Dw\s?(.+)$/, # Yahoo Mail (pl)
|
252
|
+
/\s*Копия\s?:(.+)$/, # Yahoo Mail (ru)
|
253
|
+
/\s*Kópia\s?:(.+)$/, # Yahoo Mail (sk)
|
254
|
+
/\s*Kopia\s?:(.+)$/, # Yahoo Mail (sv)
|
255
|
+
/\s*Копія\s?:(.+)$/ # Yahoo Mail (uk)
|
256
|
+
].freeze
|
257
|
+
|
258
|
+
ORIGINAL_REPLY_TO = [
|
259
|
+
/^\s*Reply-To\s?:(.+)$/, # Apple Mail (en)
|
260
|
+
/^\s*Odgovori na\s?:(.+)$/, # Apple Mail (hr)
|
261
|
+
/^\s*Odpověď na\s?:(.+)$/, # Apple Mail (cs)
|
262
|
+
/^\s*Svar til\s?:(.+)$/, # Apple Mail (da)
|
263
|
+
/^\s*Antwoord aan\s?:(.+)$/, # Apple Mail (nl)
|
264
|
+
/^\s*Vastaus\s?:(.+)$/, # Apple Mail (fi)
|
265
|
+
/^\s*Répondre à\s?:(.+)$/, # Apple Mail (fr)
|
266
|
+
/^\s*Antwort an\s?:(.+)$/, # Apple Mail (de)
|
267
|
+
/^\s*Válaszcím\s?:(.+)$/, # Apple Mail (hu)
|
268
|
+
/^\s*Rispondi a\s?:(.+)$/, # Apple Mail (it)
|
269
|
+
/^\s*Svar til\s?:(.+)$/, # Apple Mail (no)
|
270
|
+
/^\s*Odpowiedź-do\s?:(.+)$/, # Apple Mail (pl)
|
271
|
+
/^\s*Responder A\s?:(.+)$/, # Apple Mail (pt)
|
272
|
+
/^\s*Responder a\s?:(.+)$/, # Apple Mail (pt-br, es)
|
273
|
+
/^\s*Răspuns către\s?:(.+)$/, # Apple Mail (ro)
|
274
|
+
/^\s*Ответ-Кому\s?:(.+)$/, # Apple Mail (ru)
|
275
|
+
/^\s*Odpovedať-Pre\s?:(.+)$/, # Apple Mail (sk)
|
276
|
+
/^\s*Svara till\s?:(.+)$/, # Apple Mail (sv)
|
277
|
+
/^\s*Yanıt Adresi\s?:(.+)$/, # Apple Mail (tr)
|
278
|
+
/^\s*Кому відповісти\s?:(.+)$/ # Apple Mail (uk)
|
279
|
+
].freeze
|
280
|
+
|
281
|
+
ORIGINAL_DATE = [
|
282
|
+
/^\s*Date\s?:(.+)$/, # Apple Mail (en, fr), Gmail (all locales), New Outlook 2019 (en, fr), Thunderbird (da, en, fr)
|
283
|
+
/^\s*Datum\s?:(.+)$/, # Apple Mail (cs, de, hr, nl, sv), New Outlook 2019 (cs, de, nl, sv), Thunderbird (cs, de, hr, nl, sv)
|
284
|
+
/^\s*Dato\s?:(.+)$/, # Apple Mail (da, no), New Outlook 2019 (da), Thunderbird (no)
|
285
|
+
/^\s*Fecha\s?:(.+)$/, # Apple Mail (es), New Outlook 2019 (es), Thunderbird (es)
|
286
|
+
/^\s*Päivämäärä\s?:(.+)$/, # Apple Mail (fi), New Outlook 2019 (fi)
|
287
|
+
/^\s*Dátum\s?:(.+)$/, # Apple Mail (hu, sk), New Outlook 2019 (sk), Thunderbird (hu, sk)
|
288
|
+
/^\s*Data\s?:(.+)$/, # Apple Mail (it, pl, pt, pt-br), New Outlook 2019 (it, pl, pt, pt-br), Thunderbird (it, pl, pt, pt-br)
|
289
|
+
/^\s*Dată\s?:(.+)$/, # Apple Mail (ro), Thunderbird (ro)
|
290
|
+
/^\s*Дата\s?:(.+)$/, # Apple Mail (ru, uk), New Outlook 2019 (ru), Thunderbird (ru, uk)
|
291
|
+
/^\s*Tarih\s?:(.+)$/, # Apple Mail (tr), Thunderbird (tr)
|
292
|
+
/^\s*Sent\s?:(.+)$/, # Outlook Live (all locales)
|
293
|
+
/^\s*Päiväys\s?:(.+)$/ # Thunderbird (fi)
|
294
|
+
].freeze
|
295
|
+
|
296
|
+
ORIGINAL_DATE_LAX = [
|
297
|
+
/\s*Datum\s?:(.+)$/m, # Yahoo Mail (cs)
|
298
|
+
/\s*Sendt\s?:(.+)$/m, # Yahoo Mail (da, no)
|
299
|
+
/\s*Gesendet\s?:(.+)$/m, # Yahoo Mail (de)
|
300
|
+
/\s*Sent\s?:(.+)$/m, # Yahoo Mail (en)
|
301
|
+
/\s*Enviado\s?:(.+)$/m, # Yahoo Mail (es, pt, pt-br)
|
302
|
+
/\s*Envoyé\s?:(.+)$/m, # Yahoo Mail (fr)
|
303
|
+
/\s*Lähetetty\s?:(.+)$/m, # Yahoo Mail (fi)
|
304
|
+
/\s*Elküldve\s?:(.+)$/m, # Yahoo Mail (hu)
|
305
|
+
/\s*Inviato\s?:(.+)$/m, # Yahoo Mail (it)
|
306
|
+
/\s*Verzonden\s?:(.+)$/m, # Yahoo Mail (it)
|
307
|
+
/\s*Wysłano\s?:(.+)$/m, # Yahoo Mail (pl)
|
308
|
+
/\s*Trimis\s?:(.+)$/m, # Yahoo Mail (ro)
|
309
|
+
/\s*Отправлено\s?:(.+)$/m, # Yahoo Mail (ru)
|
310
|
+
/\s*Odoslané\s?:(.+)$/m, # Yahoo Mail (sk)
|
311
|
+
/\s*Skickat\s?:(.+)$/m, # Yahoo Mail (sv)
|
312
|
+
/\s*Gönderilen\s?:(.+)$/m, # Yahoo Mail (tr)
|
313
|
+
/\s*Відправлено\s?:(.+)$/m # Yahoo Mail (uk)
|
314
|
+
].freeze
|
315
|
+
|
316
|
+
MAILBOXES_SEPARATORS = [
|
317
|
+
",", # Apple Mail, Gmail, New Outlook 2019, Thunderbird
|
318
|
+
";" # Outlook Live, Yahoo Mail
|
319
|
+
].freeze
|
320
|
+
|
321
|
+
MAILBOX = [
|
322
|
+
/^(.+?)\s?\n?\s*[\[|<]mailto:(.+?)[\]|>]/, # "Walter Sheltan <mailto:walter.sheltan@acme.com>" or "Walter Sheltan [mailto:walter.sheltan@acme.com]" or "walter.sheltan@acme.com <mailto:walter.sheltan@acme.com>"
|
323
|
+
/^'(.+?)'\s?\n?\s*[\[|<](.+?)[\]|>]/, # 'Walter Sheltan' <walter.sheltan@acme.com>" or "'Walter Sheltan' [walter.sheltan@acme.com]" or "'walter.sheltan@acme.com' <walter.sheltan@acme.com>"
|
324
|
+
/^"'(.+?)'"\s?\n?\s*[\[|<](.+?)[\]|>]/, # ""'Walter Sheltan'" <walter.sheltan@acme.com>" or ""'Walter Sheltan'" [walter.sheltan@acme.com]" or ""'walter.sheltan@acme.com'" <walter.sheltan@acme.com>"
|
325
|
+
/^"(.+?)"\s?\n?\s*[\[|<](.+?)[\]|>]/, # ""Walter Sheltan" <walter.sheltan@acme.com>" or ""Walter Sheltan" [walter.sheltan@acme.com]" or ""walter.sheltan@acme.com" <walter.sheltan@acme.com>"
|
326
|
+
/^([^,;]+?)\s?\n?\s*[\[|<](.+?)[\]|>]/, # "Walter Sheltan <walter.sheltan@acme.com>" or "Walter Sheltan [walter.sheltan@acme.com]" or "walter.sheltan@acme.com <walter.sheltan@acme.com>"
|
327
|
+
/^(.?)\s?\n?\s*[\[|<](.+?)[\]|>]/, # "<walter.sheltan@acme.com>"
|
328
|
+
/^([^\s@]+@[^\s@]+\.[^\s@,]+)/ # "walter.sheltan@acme.com"
|
329
|
+
].freeze
|
330
|
+
end
|
331
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module EmailForwardParser
|
2
|
+
module Utils
|
3
|
+
def self.match_regexes(regexes, str)
|
4
|
+
regexes.find do |regex|
|
5
|
+
match = str.match(regex)
|
6
|
+
|
7
|
+
return match unless match.to_a.empty?
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.split_regexes(regexes, str)
|
12
|
+
regexes.find do |regex|
|
13
|
+
match = str.split(regex)
|
14
|
+
|
15
|
+
return match if match.length > 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.replace_regexes(regexes, str)
|
20
|
+
match = nil
|
21
|
+
|
22
|
+
regexes.each do |regex|
|
23
|
+
match = str.gsub(regex, "")
|
24
|
+
|
25
|
+
# A successful replace must return a smaller string than the input
|
26
|
+
|
27
|
+
break if match.length < str.length
|
28
|
+
end
|
29
|
+
|
30
|
+
match
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "email_forward_parser/version"
|
4
|
+
require_relative "email_forward_parser/parser"
|
5
|
+
require_relative "email_forward_parser/original_email_parser"
|
6
|
+
|
7
|
+
module EmailForwardParser
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
def self.read(body:, subject: nil)
|
11
|
+
parser = Parser.new
|
12
|
+
email = {}
|
13
|
+
result = {}
|
14
|
+
|
15
|
+
# Check if email was forwarded or not (via the subject)
|
16
|
+
parsed_subject = parser.parse_subject(subject) if subject
|
17
|
+
|
18
|
+
forwarded = parsed_subject || false
|
19
|
+
|
20
|
+
# Check if email was forwarded or not (via the body)
|
21
|
+
if !subject || forwarded
|
22
|
+
result = parser.parse_body(body, forwarded:)
|
23
|
+
|
24
|
+
if result[:email]
|
25
|
+
forwarded = true
|
26
|
+
|
27
|
+
email = OriginalEmailParser.new(result[:email], result[:body]).call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
message = if result[:message] && result[:message].empty?
|
32
|
+
nil
|
33
|
+
else
|
34
|
+
result[:message]
|
35
|
+
end
|
36
|
+
{
|
37
|
+
forwarded:,
|
38
|
+
|
39
|
+
message:,
|
40
|
+
|
41
|
+
email: {
|
42
|
+
body: email[:body],
|
43
|
+
|
44
|
+
from: {
|
45
|
+
address: email.dig(:from, :address),
|
46
|
+
name: email.dig(:from, :name)
|
47
|
+
},
|
48
|
+
|
49
|
+
to: email[:to],
|
50
|
+
|
51
|
+
cc: email[:cc],
|
52
|
+
|
53
|
+
subject: parsed_subject || email[:subject],
|
54
|
+
date: email[:date]
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: email_forward_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Collins
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-06-29 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- dev@buildr.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".standard.yml"
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- email_forward_parser.gemspec
|
26
|
+
- lib/email_forward_parser.rb
|
27
|
+
- lib/email_forward_parser/mailbox_parser.rb
|
28
|
+
- lib/email_forward_parser/original_email_parser.rb
|
29
|
+
- lib/email_forward_parser/parser.rb
|
30
|
+
- lib/email_forward_parser/regexes.rb
|
31
|
+
- lib/email_forward_parser/utils.rb
|
32
|
+
- lib/email_forward_parser/version.rb
|
33
|
+
homepage: https://github.com/buildrtech/email_forward_parser
|
34
|
+
licenses:
|
35
|
+
- Nonstandard
|
36
|
+
metadata: {}
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.2.2
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubygems_version: 3.4.12
|
53
|
+
signing_key:
|
54
|
+
specification_version: 4
|
55
|
+
summary: Parse forwarded emails from body and subject
|
56
|
+
test_files: []
|