email_forward_parser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|