sisimai 4.25.16 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +412 -393
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +140 -78
- data/README.md +290 -143
- 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 +23 -18
- 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 -326
- 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 +12 -12
- 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 -20
- 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/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
|