sisimai 4.25.17 → 5.0.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 +4 -4
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +406 -407
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +12 -12
- data/README-JA.md +142 -94
- data/README.md +282 -150
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +20 -16
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -325
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -45
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +13 -18
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +41 -21
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
@@ -1,14 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Activehunter parses a bounce email which created by
|
3
|
-
# TransWARE Active!hunter.
|
2
|
+
# Sisimai::Lhost::Activehunter parses a bounce email which created by TransWARE Active!hunter.
|
4
3
|
# Methods in the module are called from only Sisimai::Message.
|
5
4
|
module Activehunter
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Activehunter.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
12
10
|
StartingOf = { message: [' ----- The following addresses had permanent fatal errors -----'] }.freeze
|
13
11
|
|
14
12
|
# Parse bounce messages from TransWARE Active!hunter
|
@@ -16,21 +14,21 @@ module Sisimai::Lhost
|
|
16
14
|
# @param [String] mbody Message body of a bounce email
|
17
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
18
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
19
|
-
def
|
17
|
+
def inquire(mhead, mbody)
|
20
18
|
# :from => %r/\A"MAILER-DAEMON"/,
|
21
19
|
# :subject => %r/FAILURE NOTICE :/,
|
22
20
|
return nil unless mhead['x-ahmailid']
|
23
21
|
|
24
22
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
25
|
-
|
26
|
-
bodyslices =
|
23
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
24
|
+
bodyslices = emailparts[0].split("\n")
|
27
25
|
readcursor = 0 # (Integer) Points the current cursor position
|
28
26
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
29
27
|
v = nil
|
30
28
|
|
31
29
|
while e = bodyslices.shift do
|
32
|
-
# Read error messages and delivery status lines from the head of the email
|
33
|
-
#
|
30
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
31
|
+
# line of the beginning of the original message.
|
34
32
|
if readcursor == 0
|
35
33
|
# Beginning of the bounce message or delivery status part
|
36
34
|
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
@@ -47,29 +45,29 @@ module Sisimai::Lhost
|
|
47
45
|
# 550 sorry, no mailbox here by that name (#5.1.1 - chkusr)
|
48
46
|
v = dscontents[-1]
|
49
47
|
|
50
|
-
if
|
48
|
+
if e.start_with?('>>> ') && e.index('@') > 1
|
51
49
|
# >>> kijitora@example.org <kijitora@example.org>
|
52
50
|
if v['recipient']
|
53
51
|
# There are multiple recipient addresses in the message body.
|
54
52
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
55
53
|
v = dscontents[-1]
|
56
54
|
end
|
57
|
-
v['recipient'] =
|
55
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.size])
|
58
56
|
v['diagnosis'] = ''
|
59
57
|
recipients += 1
|
60
58
|
else
|
61
59
|
# ----- Transcript of session follows -----
|
62
60
|
# 550 sorry, no mailbox here by that name (#5.1.1 - chkusr)
|
63
|
-
next
|
61
|
+
next if e[0, 1].ord < 48
|
62
|
+
next if e[0, 1].ord > 122
|
64
63
|
next unless v['diagnosis'].empty?
|
65
64
|
v['diagnosis'] = e
|
66
65
|
end
|
67
66
|
end
|
68
67
|
return nil unless recipients > 0
|
69
68
|
|
70
|
-
require 'sisimai/string'
|
71
69
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
72
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
70
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
73
71
|
end
|
74
72
|
def description; return 'TransWARE Active!hunter'; end
|
75
73
|
end
|
data/lib/sisimai/lhost/amavis.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Amavis parses a bounce email which created by
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Amavis parses a bounce email which created by amavsid-new. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Amavis
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Amavis.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
11
10
|
StartingOf = { message: ['The message '] }.freeze
|
12
11
|
MessagesOf = {
|
13
12
|
# amavisd-new-2.11.1/amavisd:1840|%smtp_reason_by_ccat = (
|
@@ -75,25 +74,24 @@ module Sisimai::Lhost
|
|
75
74
|
# @return [Hash] Bounce data list and message/rfc822 part
|
76
75
|
# @return [Nil] it failed to parse or the arguments are missing
|
77
76
|
# @since v4.25.0
|
78
|
-
def
|
77
|
+
def inquire(mhead, mbody)
|
79
78
|
# From: "Content-filter at neko1.example.jp" <postmaster@neko1.example.jp>
|
80
79
|
# Subject: Undeliverable mail, MTA-BLOCKED
|
81
80
|
return nil unless mhead['from'].to_s.start_with?('"Content-filter at ')
|
82
81
|
|
83
|
-
require 'sisimai/rfc1894'
|
84
82
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
85
83
|
permessage = {} # (Hash) Store values of each Per-Message field
|
86
84
|
|
87
85
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
88
|
-
|
89
|
-
bodyslices =
|
86
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
87
|
+
bodyslices = emailparts[0].split("\n")
|
90
88
|
readcursor = 0 # (Integer) Points the current cursor position
|
91
89
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
92
90
|
v = nil
|
93
91
|
|
94
92
|
while e = bodyslices.shift do
|
95
|
-
# Read error messages and delivery status lines from the head of the email
|
96
|
-
#
|
93
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
94
|
+
# line of the beginning of the original message.
|
97
95
|
|
98
96
|
if readcursor == 0
|
99
97
|
# Beginning of the bounce message or message/delivery-status part
|
@@ -133,7 +131,7 @@ module Sisimai::Lhost
|
|
133
131
|
next unless fieldtable[o[0]]
|
134
132
|
v[fieldtable[o[0]]] = o[2]
|
135
133
|
|
136
|
-
next unless f
|
134
|
+
next unless f
|
137
135
|
permessage[fieldtable[o[0]]] = o[2]
|
138
136
|
end
|
139
137
|
end
|
@@ -148,8 +146,7 @@ module Sisimai::Lhost
|
|
148
146
|
MessagesOf.each_key do |p|
|
149
147
|
# Try to detect an error reason
|
150
148
|
MessagesOf[p].each do |r|
|
151
|
-
# Try to find an error message including lower-cased string
|
152
|
-
# defined in MessagesOf constant
|
149
|
+
# Try to find an error message including lower-cased string defined in MessagesOf constant
|
153
150
|
next unless q.include?(r)
|
154
151
|
e['reason'] = p
|
155
152
|
throw :DETECT_REASON
|
@@ -157,7 +154,7 @@ module Sisimai::Lhost
|
|
157
154
|
end
|
158
155
|
end
|
159
156
|
end
|
160
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
157
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
161
158
|
end
|
162
159
|
def description; return 'amavisd-new: https://www.amavis.org/'; end
|
163
160
|
end
|
@@ -1,15 +1,13 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::AmazonSES parses a bounce email which created by
|
3
|
-
# Amazon Simple Email Service.
|
2
|
+
# Sisimai::Lhost::AmazonSES parses a bounce email which created by Amazon Simple Email Service.
|
4
3
|
# Methods in the module are called from only Sisimai::Message.
|
5
4
|
module AmazonSES
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/AmazonSES.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
# https://aws.amazon.com/ses/
|
11
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
12
|
-
|
10
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
13
11
|
StartingOf = {
|
14
12
|
message: ['The following message to <', 'An error occurred while trying to deliver the mail'],
|
15
13
|
}.freeze
|
@@ -20,14 +18,14 @@ module Sisimai::Lhost
|
|
20
18
|
# @param [String] mbody Message body of a bounce email
|
21
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
22
20
|
# @return [Nil] it failed to parse or the arguments are missing
|
23
|
-
def
|
21
|
+
def inquire(mhead, mbody)
|
24
22
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
25
23
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
26
24
|
|
27
25
|
if mbody.start_with?('{')
|
28
26
|
# The message body is JSON string
|
29
27
|
return nil unless mhead['x-amz-sns-message-id']
|
30
|
-
return nil if
|
28
|
+
return nil if mhead['x-amz-sns-message-id'].empty?
|
31
29
|
|
32
30
|
# https://docs.aws.amazon.com/en_us/ses/latest/DeveloperGuide/notification-contents.html
|
33
31
|
bouncetype = {
|
@@ -102,7 +100,7 @@ module Sisimai::Lhost
|
|
102
100
|
while e = r.shift do
|
103
101
|
# 'bouncedRecipients' => [ { 'emailAddress' => 'bounce@si...' }, ... ]
|
104
102
|
# 'complainedRecipients' => [ { 'emailAddress' => 'complaint@si...' }, ... ]
|
105
|
-
next unless Sisimai::
|
103
|
+
next unless Sisimai::Address.is_emailaddress(e['emailAddress'])
|
106
104
|
|
107
105
|
v = dscontents[-1]
|
108
106
|
if v['recipient']
|
@@ -123,22 +121,22 @@ module Sisimai::Lhost
|
|
123
121
|
v['action'] = e['action']
|
124
122
|
v['status'] = e['status']
|
125
123
|
|
126
|
-
if
|
124
|
+
if p0 = e['diagnosticCode'].index(';') || -1; p0 > 3
|
127
125
|
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
128
|
-
v['spec']
|
129
|
-
v['diagnosis'] =
|
126
|
+
v['spec'] = e['diagnosticCode'][0, p0].upcase
|
127
|
+
v['diagnosis'] = e['diagnosticCode'][p0 + 2, e['diagnosticCode'].size]
|
130
128
|
else
|
131
129
|
v['diagnosis'] = e['diagnosticCode']
|
132
130
|
end
|
133
131
|
|
134
132
|
# 'reportingMTA' => 'dsn; a27-23.smtp-out.us-west-2.amazonses.com',
|
135
|
-
|
133
|
+
p0 = o['reportingMTA'].index('dsn; ')
|
134
|
+
v['lhost'] = Sisimai::String.sweep(o['reportingMTA'][p0 + 5, o['reportingMTA'].size]) if p0
|
136
135
|
|
137
|
-
if bouncetype[o['bounceType']] &&
|
138
|
-
bouncetype[o['bounceType']][o['bounceSubType']]
|
136
|
+
if bouncetype[o['bounceType']] && bouncetype[o['bounceType']][o['bounceSubType']]
|
139
137
|
# 'bounce' => {
|
140
|
-
#
|
141
|
-
#
|
138
|
+
# 'bounceType' => 'Permanent',
|
139
|
+
# 'bounceSubType' => 'General'
|
142
140
|
# },
|
143
141
|
v['reason'] = bouncetype[o['bounceType']][o['bounceSubType']]
|
144
142
|
end
|
@@ -159,15 +157,15 @@ module Sisimai::Lhost
|
|
159
157
|
|
160
158
|
while e = r.shift do
|
161
159
|
# 'delivery' => {
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
#
|
170
|
-
next unless Sisimai::
|
160
|
+
# 'timestamp' => '2016-11-23T12:01:03.512Z',
|
161
|
+
# 'processingTimeMillis' => 3982,
|
162
|
+
# 'reportingMTA' => 'a27-29.smtp-out.us-west-2.amazonses.com',
|
163
|
+
# 'recipients' => [
|
164
|
+
# 'success@simulator.amazonses.com'
|
165
|
+
# ],
|
166
|
+
# 'smtpResponse' => '250 2.6.0 Message received'
|
167
|
+
# },
|
168
|
+
next unless Sisimai::Address.is_emailaddress(e)
|
171
169
|
|
172
170
|
v = dscontents[-1]
|
173
171
|
if v['recipient']
|
@@ -180,7 +178,6 @@ module Sisimai::Lhost
|
|
180
178
|
v['lhost'] = o['reportingMTA'] || ''
|
181
179
|
v['diagnosis'] = o['smtpResponse'] || ''
|
182
180
|
v['status'] = Sisimai::SMTP::Status.find(v['diagnosis']) || ''
|
183
|
-
v['replycode'] = Sisimai::SMTP::Reply.find(v['diagnosis']) || ''
|
184
181
|
v['reason'] = 'delivered'
|
185
182
|
v['action'] = 'delivered'
|
186
183
|
|
@@ -188,8 +185,7 @@ module Sisimai::Lhost
|
|
188
185
|
v['date'].sub!(/[.]\d+Z\z/, '')
|
189
186
|
end
|
190
187
|
else
|
191
|
-
# The value of "notificationType" is not any of "Bounce", "Complaint",
|
192
|
-
# or "Delivery".
|
188
|
+
# The value of "notificationType" is not any of "Bounce", "Complaint", or "Delivery".
|
193
189
|
return nil
|
194
190
|
end
|
195
191
|
return nil unless recipients > 0
|
@@ -232,15 +228,15 @@ module Sisimai::Lhost
|
|
232
228
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
233
229
|
permessage = {} # (Hash) Store values of each Per-Message field
|
234
230
|
|
235
|
-
|
236
|
-
bodyslices =
|
231
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
232
|
+
bodyslices = emailparts[0].split("\n")
|
237
233
|
readslices = ['']
|
238
234
|
readcursor = 0 # (Integer) Points the current cursor position
|
239
235
|
v = nil
|
240
236
|
|
241
237
|
while e = bodyslices.shift do
|
242
|
-
# Read error messages and delivery status lines from the head of the email
|
243
|
-
#
|
238
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
239
|
+
# line of the beginning of the original message.
|
244
240
|
readslices << e # Save the current line for the next loop
|
245
241
|
|
246
242
|
if readcursor == 0
|
@@ -283,14 +279,14 @@ module Sisimai::Lhost
|
|
283
279
|
next unless fieldtable[o[0]]
|
284
280
|
v[fieldtable[o[0]]] = o[2]
|
285
281
|
|
286
|
-
next unless f
|
282
|
+
next unless f
|
287
283
|
permessage[fieldtable[o[0]]] = o[2]
|
288
284
|
end
|
289
285
|
else
|
290
286
|
# Continued line of the value of Diagnostic-Code field
|
291
287
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
292
|
-
next unless
|
293
|
-
v['diagnosis'] << ' ' <<
|
288
|
+
next unless e.start_with?(' ')
|
289
|
+
v['diagnosis'] << ' ' << e
|
294
290
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
295
291
|
end
|
296
292
|
end
|
@@ -313,16 +309,16 @@ module Sisimai::Lhost
|
|
313
309
|
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
314
310
|
|
315
311
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].to_s.tr("\n", ' '))
|
316
|
-
if e['status'].to_s.
|
312
|
+
if e['status'].to_s.end_with?('.0.0', '.1.0')
|
317
313
|
# Get other D.S.N. value from the error message
|
314
|
+
# 5.1.0 - Unknown address error 550-'5.7.1 ...
|
318
315
|
errormessage = e['diagnosis']
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
errormessage = cv[1]
|
323
|
-
end
|
316
|
+
p1 = e['diagnosis'].index("-'"); p1 = e['diagnosis'].index('-"') unless p1
|
317
|
+
p2 = e['diagnosis'].rindex("' "); p2 = e['diagnosis'].rindex('" ') unless p2
|
318
|
+
errormessage = e['diagnosis'][p1 + 2, p2 - p1 - 2] if p1 && p2
|
324
319
|
e['status'] = Sisimai::SMTP::Status.find(errormessage) || e['status']
|
325
320
|
end
|
321
|
+
e['replycode'] ||= Sisimai::SMTP::Reply.find(e['diagnosis'], e['status'])
|
326
322
|
|
327
323
|
MessagesOf.each_key do |r|
|
328
324
|
# Verify each regular expression of session errors
|
@@ -332,7 +328,7 @@ module Sisimai::Lhost
|
|
332
328
|
end
|
333
329
|
end
|
334
330
|
|
335
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
331
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
336
332
|
end # END of a parser for email message
|
337
333
|
|
338
334
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::AmazonWorkMail parses a bounce email which created by
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::AmazonWorkMail parses a bounce email which created by Amazon WorkMail. Methods
|
3
|
+
# in the module are called from only Sisimai::Message.
|
4
4
|
module AmazonWorkMail
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/AmazonWorkMail.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
# https://aws.amazon.com/workmail/
|
10
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
10
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
12
11
|
StartingOf = { message: ['Technical report:'] }.freeze
|
13
12
|
|
14
13
|
# Parse bounce messages from Amazon WorkMail
|
@@ -16,7 +15,7 @@ module Sisimai::Lhost
|
|
16
15
|
# @param [String] mbody Message body of a bounce email
|
17
16
|
# @return [Hash] Bounce data list and message/rfc822 part
|
18
17
|
# @return [Nil] it failed to parse or the arguments are missing
|
19
|
-
def
|
18
|
+
def inquire(mhead, mbody)
|
20
19
|
# X-Mailer: Amazon WorkMail
|
21
20
|
# X-Original-Mailer: Amazon WorkMail
|
22
21
|
# X-Ses-Outgoing: 2016.01.14-54.240.27.159
|
@@ -36,15 +35,15 @@ module Sisimai::Lhost
|
|
36
35
|
permessage = {} # (Hash) Store values of each Per-Message field
|
37
36
|
|
38
37
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
39
|
-
|
40
|
-
bodyslices =
|
38
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
39
|
+
bodyslices = emailparts[0].split("\n")
|
41
40
|
readcursor = 0 # (Integer) Points the current cursor position
|
42
41
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
43
42
|
v = nil
|
44
43
|
|
45
44
|
while e = bodyslices.shift do
|
46
|
-
# Read error messages and delivery status lines from the head of the email
|
47
|
-
#
|
45
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
46
|
+
# line of the beginning of the original message.
|
48
47
|
|
49
48
|
if readcursor == 0
|
50
49
|
# Beginning of the bounce message or message/delivery-status part
|
@@ -84,7 +83,7 @@ module Sisimai::Lhost
|
|
84
83
|
next unless fieldtable[o[0]]
|
85
84
|
v[fieldtable[o[0]]] = o[2]
|
86
85
|
|
87
|
-
next unless f
|
86
|
+
next unless f
|
88
87
|
permessage[fieldtable[o[0]]] = o[2]
|
89
88
|
end
|
90
89
|
end
|
@@ -103,7 +102,7 @@ module Sisimai::Lhost
|
|
103
102
|
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
104
103
|
|
105
104
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
106
|
-
if e['status'].to_s.
|
105
|
+
if e['status'].to_s.end_with?('.0.0', '.1.0')
|
107
106
|
# Get other D.S.N. value from the error message
|
108
107
|
errormessage = e['diagnosis']
|
109
108
|
|
@@ -114,15 +113,13 @@ module Sisimai::Lhost
|
|
114
113
|
e['status'] = Sisimai::SMTP::Status.find(errormessage) || e['status']
|
115
114
|
end
|
116
115
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
122
|
-
e['reason'] ||= Sisimai::SMTP::Status.name(e['status']) || ''
|
116
|
+
# 554 4.4.7 Message expired: unable to deliver in 840 minutes.
|
117
|
+
# <421 4.4.2 Connection timed out>
|
118
|
+
e['replycode'] = Sisimai::SMTP::Reply.find(e['diagnosis']) || ''
|
119
|
+
e['reason'] ||= Sisimai::SMTP::Status.name(e['status']) || ''
|
123
120
|
end
|
124
121
|
|
125
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
122
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
126
123
|
end
|
127
124
|
def description; return 'Amazon WorkMail: https://aws.amazon.com/workmail/'; end
|
128
125
|
end
|
data/lib/sisimai/lhost/aol.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Aol parses a bounce email which created by Aol Mail.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Aol parses a bounce email which created by Aol Mail. Methods in the module are
|
3
|
+
# called from only Sisimai::Message.
|
4
4
|
module Aol
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Aol.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
|
12
11
|
MessagesOf = {
|
13
12
|
'hostunknown' => ['Host or domain name not found'],
|
@@ -19,7 +18,7 @@ module Sisimai::Lhost
|
|
19
18
|
# @param [String] mbody Message body of a bounce email
|
20
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
21
20
|
# @return [Nil] it failed to parse or the arguments are missing
|
22
|
-
def
|
21
|
+
def inquire(mhead, mbody)
|
23
22
|
# X-AOL-IP: 192.0.2.135
|
24
23
|
# X-AOL-VSS-INFO: 5600.1067/98281
|
25
24
|
# X-AOL-VSS-CODE: clean
|
@@ -32,21 +31,20 @@ module Sisimai::Lhost
|
|
32
31
|
# X-Outbound-Mail-Relay-Sender: rfc822; shironeko@aol.example.jp
|
33
32
|
return nil unless mhead['x-aol-ip']
|
34
33
|
|
35
|
-
require 'sisimai/rfc1894'
|
36
34
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
37
35
|
permessage = {} # (Hash) Store values of each Per-Message field
|
38
36
|
|
39
37
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
40
|
-
|
41
|
-
bodyslices =
|
38
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
39
|
+
bodyslices = emailparts[0].split("\n")
|
42
40
|
readslices = ['']
|
43
41
|
readcursor = 0 # (Integer) Points the current cursor position
|
44
42
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
45
43
|
v = nil
|
46
44
|
|
47
45
|
while e = bodyslices.shift do
|
48
|
-
# Read error messages and delivery status lines from the head of the email
|
49
|
-
#
|
46
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
47
|
+
# line of the beginning of the original message.
|
50
48
|
readslices << e # Save the current line for the next loop
|
51
49
|
|
52
50
|
if readcursor == 0
|
@@ -87,14 +85,14 @@ module Sisimai::Lhost
|
|
87
85
|
next unless fieldtable[o[0]]
|
88
86
|
v[fieldtable[o[0]]] = o[2]
|
89
87
|
|
90
|
-
next unless f
|
88
|
+
next unless f
|
91
89
|
permessage[fieldtable[o[0]]] = o[2]
|
92
90
|
end
|
93
91
|
else
|
94
92
|
# Continued line of the value of Diagnostic-Code field
|
95
93
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
96
|
-
next unless
|
97
|
-
v['diagnosis'] << ' ' <<
|
94
|
+
next unless e.start_with?(' ')
|
95
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
98
96
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
99
97
|
end
|
100
98
|
end
|
@@ -119,7 +117,7 @@ module Sisimai::Lhost
|
|
119
117
|
end
|
120
118
|
end
|
121
119
|
|
122
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
120
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
123
121
|
end
|
124
122
|
def description; return 'Aol Mail: https://www.aol.com'; end
|
125
123
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::ApacheJames parses a bounce email which created by ApacheJames.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::ApacheJames parses a bounce email which created by ApacheJames. Methods in the
|
3
|
+
# module are called from only Sisimai::Message.
|
4
4
|
module ApacheJames
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/ApacheJames.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = {
|
12
11
|
# apache-james-2.3.2/src/java/org/apache/james/transport/mailets/
|
13
12
|
# AbstractNotify.java|124: out.println("Error message below:");
|
@@ -21,7 +20,7 @@ module Sisimai::Lhost
|
|
21
20
|
# @param [String] mbody Message body of a bounce email
|
22
21
|
# @return [Hash] Bounce data list and message/rfc822 part
|
23
22
|
# @return [Nil] it failed to parse or the arguments are missing
|
24
|
-
def
|
23
|
+
def inquire(mhead, mbody)
|
25
24
|
match = 0
|
26
25
|
match += 1 if mhead['subject'] == '[BOUNCE]'
|
27
26
|
match += 1 if mhead['message-id'].to_s.include?('.JavaMail.')
|
@@ -29,18 +28,18 @@ module Sisimai::Lhost
|
|
29
28
|
return nil unless match > 0
|
30
29
|
|
31
30
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
32
|
-
|
33
|
-
bodyslices =
|
31
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
32
|
+
bodyslices = emailparts[0].split("\n")
|
34
33
|
readcursor = 0 # (Integer) Points the current cursor position
|
35
34
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
36
|
-
|
35
|
+
issuedcode = '' # (String) Alternative diagnostic message
|
37
36
|
subjecttxt = nil # (String) Alternative Subject text
|
38
37
|
gotmessage = nil # (Boolean) Flag for error message
|
39
38
|
v = nil
|
40
39
|
|
41
40
|
while e = bodyslices.shift do
|
42
|
-
# Read error messages and delivery status lines from the head of the email
|
43
|
-
#
|
41
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
42
|
+
# line of the beginning of the original message.
|
44
43
|
|
45
44
|
if readcursor == 0
|
46
45
|
# Beginning of the bounce message or delivery status part
|
@@ -61,23 +60,23 @@ module Sisimai::Lhost
|
|
61
60
|
# Number of lines: 64
|
62
61
|
v = dscontents[-1]
|
63
62
|
|
64
|
-
if
|
63
|
+
if e.start_with?(' RCPT TO: ')
|
65
64
|
# RCPT TO: kijitora@example.org
|
66
65
|
if v['recipient']
|
67
66
|
# There are multiple recipient addresses in the message body.
|
68
67
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
69
68
|
v = dscontents[-1]
|
70
69
|
end
|
71
|
-
v['recipient'] =
|
70
|
+
v['recipient'] = e[12, e.size]
|
72
71
|
recipients += 1
|
73
72
|
|
74
|
-
elsif
|
73
|
+
elsif e.start_with?(' Sent date: ')
|
75
74
|
# Sent date: Thu Apr 29 01:20:50 JST 2015
|
76
|
-
v['date'] =
|
75
|
+
v['date'] = e[13, e.size]
|
77
76
|
|
78
|
-
elsif
|
77
|
+
elsif e.start_with?(' Subject: ')
|
79
78
|
# Subject: Nyaaan
|
80
|
-
subjecttxt =
|
79
|
+
subjecttxt = e[11, e.size]
|
81
80
|
else
|
82
81
|
next if gotmessage
|
83
82
|
if v['diagnosis']
|
@@ -106,12 +105,11 @@ module Sisimai::Lhost
|
|
106
105
|
end
|
107
106
|
return nil unless recipients > 0
|
108
107
|
|
109
|
-
# Set the value of subjecttxt as a Subject if there is no original
|
110
|
-
|
111
|
-
emailsteak[1] << ('Subject: ' << subjecttxt << "\n") unless emailsteak[1] =~ /^Subject: /
|
108
|
+
# Set the value of subjecttxt as a Subject if there is no original message in the bounce mail.
|
109
|
+
emailparts[1] << ('Subject: ' << subjecttxt << "\n") unless emailparts[1].index("\nSubject:")
|
112
110
|
|
113
|
-
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] ||
|
114
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
111
|
+
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode) }
|
112
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
115
113
|
end
|
116
114
|
def description; return 'Java Apache Mail Enterprise Server'; end
|
117
115
|
end
|