sisimai 4.22.3-java → 4.22.4-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sisimai might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Benchmarks.mk +54 -0
- data/ChangeLog.md +23 -2
- data/Developers.mk +42 -35
- data/Makefile +10 -0
- data/README-JA.md +13 -13
- data/README.md +14 -14
- data/lib/sisimai.rb +12 -18
- data/lib/sisimai/address.rb +64 -82
- data/lib/sisimai/arf.rb +27 -42
- data/lib/sisimai/bite/email.rb +2 -4
- data/lib/sisimai/bite/email/activehunter.rb +12 -17
- data/lib/sisimai/bite/email/amazonses.rb +30 -48
- data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
- data/lib/sisimai/bite/email/aol.rb +27 -35
- data/lib/sisimai/bite/email/apachejames.rb +17 -28
- data/lib/sisimai/bite/email/bigfoot.rb +20 -33
- data/lib/sisimai/bite/email/biglobe.rb +15 -24
- data/lib/sisimai/bite/email/courier.rb +37 -61
- data/lib/sisimai/bite/email/domino.rb +19 -28
- data/lib/sisimai/bite/email/einsundeins.rb +20 -34
- data/lib/sisimai/bite/email/exchange2003.rb +25 -43
- data/lib/sisimai/bite/email/exchange2007.rb +15 -23
- data/lib/sisimai/bite/email/exim.rb +101 -120
- data/lib/sisimai/bite/email/ezweb.rb +28 -44
- data/lib/sisimai/bite/email/facebook.rb +26 -37
- data/lib/sisimai/bite/email/fml.rb +11 -20
- data/lib/sisimai/bite/email/gmx.rb +17 -27
- data/lib/sisimai/bite/email/google.rb +19 -29
- data/lib/sisimai/bite/email/gsuite.rb +39 -48
- data/lib/sisimai/bite/email/imailserver.rb +25 -39
- data/lib/sisimai/bite/email/interscanmss.rb +19 -26
- data/lib/sisimai/bite/email/kddi.rb +20 -33
- data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
- data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
- data/lib/sisimai/bite/email/mailru.rb +40 -59
- data/lib/sisimai/bite/email/mcafee.rb +21 -35
- data/lib/sisimai/bite/email/messagelabs.rb +23 -38
- data/lib/sisimai/bite/email/messagingserver.rb +15 -27
- data/lib/sisimai/bite/email/mfilter.rb +19 -28
- data/lib/sisimai/bite/email/mxlogic.rb +31 -49
- data/lib/sisimai/bite/email/notes.rb +16 -24
- data/lib/sisimai/bite/email/office365.rb +29 -38
- data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
- data/lib/sisimai/bite/email/outlook.rb +24 -36
- data/lib/sisimai/bite/email/postfix.rb +33 -42
- data/lib/sisimai/bite/email/qmail.rb +44 -59
- data/lib/sisimai/bite/email/receivingses.rb +28 -36
- data/lib/sisimai/bite/email/sendgrid.rb +28 -37
- data/lib/sisimai/bite/email/sendmail.rb +35 -51
- data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
- data/lib/sisimai/bite/email/userdefined.rb +17 -28
- data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
- data/lib/sisimai/bite/email/verizon.rb +31 -56
- data/lib/sisimai/bite/email/x1.rb +11 -18
- data/lib/sisimai/bite/email/x2.rb +11 -23
- data/lib/sisimai/bite/email/x3.rb +10 -19
- data/lib/sisimai/bite/email/x4.rb +46 -65
- data/lib/sisimai/bite/email/x5.rb +26 -37
- data/lib/sisimai/bite/email/yahoo.rb +11 -19
- data/lib/sisimai/bite/email/yandex.rb +19 -30
- data/lib/sisimai/bite/email/zoho.rb +21 -30
- data/lib/sisimai/bite/json.rb +1 -2
- data/lib/sisimai/bite/json/amazonses.rb +20 -25
- data/lib/sisimai/bite/json/sendgrid.rb +1 -1
- data/lib/sisimai/data.rb +36 -55
- data/lib/sisimai/data/json.rb +3 -3
- data/lib/sisimai/data/yaml.rb +1 -1
- data/lib/sisimai/datetime.rb +5 -21
- data/lib/sisimai/mail.rb +4 -6
- data/lib/sisimai/mail/maildir.rb +1 -1
- data/lib/sisimai/mda.rb +41 -44
- data/lib/sisimai/message.rb +2 -3
- data/lib/sisimai/message/email.rb +42 -52
- data/lib/sisimai/message/json.rb +7 -7
- data/lib/sisimai/mime.rb +25 -23
- data/lib/sisimai/order/email.rb +2 -2
- data/lib/sisimai/order/json.rb +2 -7
- data/lib/sisimai/reason.rb +41 -46
- data/lib/sisimai/reason/blocked.rb +60 -71
- data/lib/sisimai/reason/contenterror.rb +4 -8
- data/lib/sisimai/reason/delivered.rb +1 -3
- data/lib/sisimai/reason/exceedlimit.rb +10 -20
- data/lib/sisimai/reason/expired.rb +5 -9
- data/lib/sisimai/reason/feedback.rb +1 -3
- data/lib/sisimai/reason/filtered.rb +19 -38
- data/lib/sisimai/reason/hasmoved.rb +5 -8
- data/lib/sisimai/reason/hostunknown.rb +11 -18
- data/lib/sisimai/reason/mailboxfull.rb +14 -24
- data/lib/sisimai/reason/mailererror.rb +3 -5
- data/lib/sisimai/reason/mesgtoobig.rb +15 -25
- data/lib/sisimai/reason/networkerror.rb +8 -10
- data/lib/sisimai/reason/norelaying.rb +9 -14
- data/lib/sisimai/reason/notaccept.rb +9 -21
- data/lib/sisimai/reason/onhold.rb +3 -8
- data/lib/sisimai/reason/policyviolation.rb +8 -10
- data/lib/sisimai/reason/rejected.rb +36 -49
- data/lib/sisimai/reason/securityerror.rb +11 -13
- data/lib/sisimai/reason/spamdetected.rb +23 -37
- data/lib/sisimai/reason/suspend.rb +9 -10
- data/lib/sisimai/reason/syntaxerror.rb +3 -4
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +2 -4
- data/lib/sisimai/reason/toomanyconn.rb +17 -30
- data/lib/sisimai/reason/undefined.rb +1 -3
- data/lib/sisimai/reason/userunknown.rb +28 -38
- data/lib/sisimai/reason/vacation.rb +4 -6
- data/lib/sisimai/reason/virusdetected.rb +4 -6
- data/lib/sisimai/rfc2606.rb +1 -2
- data/lib/sisimai/rfc3464.rb +87 -101
- data/lib/sisimai/rfc3834.rb +29 -39
- data/lib/sisimai/rfc5322.rb +17 -24
- data/lib/sisimai/rhost.rb +10 -7
- data/lib/sisimai/rhost/exchangeonline.rb +124 -255
- data/lib/sisimai/rhost/franceptt.rb +2 -2
- data/lib/sisimai/rhost/godaddy.rb +12 -25
- data/lib/sisimai/rhost/googleapps.rb +82 -183
- data/lib/sisimai/smtp.rb +4 -4
- data/lib/sisimai/smtp/error.rb +8 -8
- data/lib/sisimai/smtp/reply.rb +1 -1
- data/lib/sisimai/smtp/status.rb +1 -0
- data/lib/sisimai/string.rb +5 -7
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/README.md +1 -1
- data/set-of-emails/maildir/bsd/README.md +50 -50
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +4 -4
- data/lib/sisimai/skeleton.rb +0 -43
@@ -6,37 +6,33 @@ module Sisimai::Bite::Email
|
|
6
6
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/qmail.pm
|
7
7
|
require 'sisimai/bite/email'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
:begin => %r/\AHi[.] This is the qmail/,
|
22
|
-
:rfc822 => %r/\A--- Below this line is a copy of the message[.]\z/,
|
23
|
-
:error => %r/\ARemote host said:/,
|
24
|
-
:sorry => %r/\A[Ss]orry[,.][ ]/,
|
25
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
9
|
+
Indicators = Sisimai::Bite::Email.INDICATORS
|
10
|
+
StartingOf = {
|
11
|
+
# qmail-remote.c:248| if (code >= 500) {
|
12
|
+
# qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
|
13
|
+
# qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
|
14
|
+
# qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
|
15
|
+
#
|
16
|
+
# Characters: K,Z,D in qmail-qmqpc.c, qmail-send.c, qmail-rspawn.c
|
17
|
+
# K = success, Z = temporary error, D = permanent error
|
18
|
+
message: ['Hi. This is the qmail'],
|
19
|
+
rfc822: ['--- Below this line is a copy of the message.'],
|
20
|
+
error: ['Remote host said:'],
|
26
21
|
}.freeze
|
22
|
+
|
27
23
|
ReSMTP = {
|
28
24
|
# Error text regular expressions which defined in qmail-remote.c
|
29
25
|
# qmail-remote.c:225| if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
|
30
|
-
conn: %r/(?:Error:)?Connected
|
26
|
+
conn: %r/(?:Error:)?Connected to .+ but greeting failed[.]/,
|
31
27
|
# qmail-remote.c:231| if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
|
32
|
-
ehlo: %r/(?:Error:)?Connected
|
28
|
+
ehlo: %r/(?:Error:)?Connected to .+ but my name was rejected[.]/,
|
33
29
|
# qmail-remote.c:238| if (code >= 500) quit("DConnected to "," but sender was rejected");
|
34
30
|
# reason = rejected
|
35
|
-
mail: %r/(?:Error:)?Connected
|
31
|
+
mail: %r/(?:Error:)?Connected to .+ but sender was rejected[.]/,
|
36
32
|
# qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
|
37
33
|
# qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
|
38
34
|
# reason = userunknown
|
39
|
-
rcpt: %r/(?:Error:)?.+
|
35
|
+
rcpt: %r/(?:Error:)?.+ does not like recipient[.]/,
|
40
36
|
# qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
|
41
37
|
# qmail-remote.c:266| if (code >= 400) quit("Z"," failed on DATA command");
|
42
38
|
# qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
|
@@ -80,26 +76,24 @@ module Sisimai::Bite::Email
|
|
80
76
|
)
|
81
77
|
}x,
|
82
78
|
}.freeze
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
79
|
+
|
80
|
+
# qmail-send.c:922| ... (&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
|
81
|
+
ReDelaying = %r/this message has been in the queue too long[.]\z/
|
82
|
+
ReCommands = %r/Sorry, no SMTP connection got far enough; most progress was ([A-Z]{4}) /
|
83
|
+
ReIsOnHold = %r/\A[^ ]+ does not like recipient[.][ ]+.+this message has been in the queue too long[.]\z/
|
84
|
+
ReFailures = {
|
88
85
|
# qmail-local.c:589| strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)");
|
89
86
|
# qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
|
90
|
-
userunknown: %r
|
91
|
-
no[ ]mailbox[ ]here[ ]by[ ]that[ ]name
|
92
|
-
|[ ]does[ ]not[ ]like[ ]recipient[.]
|
93
|
-
)
|
94
|
-
}x,
|
87
|
+
userunknown: %r/(?:no mailbox here by that name| does not like recipient[.])/,
|
95
88
|
# error_str.c:192| X(EDQUOT,"disk quota exceeded")
|
96
|
-
mailboxfull: %r/disk
|
89
|
+
mailboxfull: %r/disk quota exceeded/,
|
97
90
|
# qmail-qmtpd.c:233| ... result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
|
98
91
|
# qmail-smtpd.c:391| ... out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return;
|
99
|
-
mesgtoobig: %r/Message
|
92
|
+
mesgtoobig: %r/Message size exceeds fixed maximum message size:/,
|
100
93
|
# qmail-remote.c:68| Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie();
|
101
94
|
# qmail-remote.c:78| Sorry, I couldn't find any host named ");
|
102
|
-
hostunknown: %r/\ASorry
|
95
|
+
hostunknown: %r/\ASorry, I couldn't find any host /,
|
96
|
+
systemfull: %r/Requested action not taken: mailbox unavailable [(]not enough free space[)]/,
|
103
97
|
systemerror: %r{(?>
|
104
98
|
bad[ ]interpreter:[ ]No[ ]such[ ]file[ ]or[ ]directory
|
105
99
|
|system[ ]error
|
@@ -109,20 +103,14 @@ module Sisimai::Bite::Email
|
|
109
103
|
networkerror: %r{Sorry(?:
|
110
104
|
[,][ ]I[ ]wasn[']t[ ]able[ ]to[ ]establish[ ]an[ ]SMTP[ ]connection
|
111
105
|
|[,][ ]I[ ]couldn[']t[ ]find[ ]a[ ]mail[ ]exchanger[ ]or[ ]IP[ ]address
|
112
|
-
|[.][ ]Although[ ]I[']m[ ]listed[ ]as[ ]a[ ]best[-]preference[ ]MX[ ]
|
113
|
-
or[ ]A[ ]for[ ]that[ ]host
|
106
|
+
|[.][ ]Although[ ]I[']m[ ]listed[ ]as[ ]a[ ]best[-]preference[ ]MX[ ]or[ ]A[ ]for[ ]that[ ]host
|
114
107
|
)
|
115
108
|
}x,
|
116
|
-
systemfull: %r/Requested action not taken: mailbox unavailable [(]not enough free space[)]/,
|
117
109
|
}.freeze
|
118
|
-
# qmail-send.c:922| ... (&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
|
119
|
-
ReDelayed = %r/this[ ]message[ ]has[ ]been[ ]in[ ]the[ ]queue[ ]too[ ]long[.]\z/x
|
120
|
-
Indicators = Sisimai::Bite::Email.INDICATORS
|
121
110
|
|
122
111
|
def description; return 'qmail'; end
|
123
112
|
def smtpagent; return 'Email::qmail'; end
|
124
113
|
def headerlist; return []; end
|
125
|
-
def pattern; return Re0; end
|
126
114
|
|
127
115
|
# Parse bounce messages from qmail
|
128
116
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -143,9 +131,10 @@ module Sisimai::Bite::Email
|
|
143
131
|
# by qmail, see http://cr.yp.to/qmail.html
|
144
132
|
# e.g.) Received: (qmail 12345 invoked for bounce); 29 Apr 2009 12:34:56 -0000
|
145
133
|
# Subject: failure notice
|
134
|
+
tryto = /\A[(]qmail[ ]+\d+[ ]+invoked[ ]+(?:for[ ]+bounce|from[ ]+network)[)]/
|
146
135
|
match = 0
|
147
|
-
match += 1 if mhead['subject']
|
148
|
-
match += 1 if mhead['received'].find { |a| a =~
|
136
|
+
match += 1 if mhead['subject'] == 'failure notice'
|
137
|
+
match += 1 if mhead['received'].find { |a| a =~ tryto }
|
149
138
|
return nil if match.zero?
|
150
139
|
|
151
140
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
@@ -156,10 +145,10 @@ module Sisimai::Bite::Email
|
|
156
145
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
157
146
|
v = nil
|
158
147
|
|
159
|
-
hasdivided.
|
148
|
+
while e = hasdivided.shift do
|
160
149
|
if readcursor.zero?
|
161
150
|
# Beginning of the bounce message or delivery status part
|
162
|
-
if e
|
151
|
+
if e.start_with?(StartingOf[:message][0])
|
163
152
|
readcursor |= Indicators[:deliverystatus]
|
164
153
|
next
|
165
154
|
end
|
@@ -167,7 +156,7 @@ module Sisimai::Bite::Email
|
|
167
156
|
|
168
157
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
169
158
|
# Beginning of the original message part
|
170
|
-
if e
|
159
|
+
if e == StartingOf[:rfc822][0]
|
171
160
|
readcursor |= Indicators[:'message-rfc822']
|
172
161
|
next
|
173
162
|
end
|
@@ -181,7 +170,6 @@ module Sisimai::Bite::Email
|
|
181
170
|
next
|
182
171
|
end
|
183
172
|
rfc822list << e
|
184
|
-
|
185
173
|
else
|
186
174
|
# Before "message/rfc822"
|
187
175
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -207,8 +195,8 @@ module Sisimai::Bite::Email
|
|
207
195
|
# Append error message
|
208
196
|
next if e.empty?
|
209
197
|
v['diagnosis'] ||= ''
|
210
|
-
v['diagnosis']
|
211
|
-
v['alterrors']
|
198
|
+
v['diagnosis'] << e + ' '
|
199
|
+
v['alterrors'] = e if e.start_with?(StartingOf[:error][0])
|
212
200
|
|
213
201
|
next if v['rhost']
|
214
202
|
if cv = e.match(ReHost)
|
@@ -221,7 +209,6 @@ module Sisimai::Bite::Email
|
|
221
209
|
|
222
210
|
require 'sisimai/string'
|
223
211
|
require 'sisimai/smtp/status'
|
224
|
-
|
225
212
|
dscontents.map do |e|
|
226
213
|
e['agent'] = self.smtpagent
|
227
214
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
@@ -237,7 +224,7 @@ module Sisimai::Bite::Email
|
|
237
224
|
|
238
225
|
unless e['command']
|
239
226
|
# Verify each regular expression of patches
|
240
|
-
if cv = e['diagnosis'].match(
|
227
|
+
if cv = e['diagnosis'].match(ReCommands)
|
241
228
|
e['command'] = cv[1].upcase
|
242
229
|
end
|
243
230
|
e['command'] ||= ''
|
@@ -249,28 +236,26 @@ module Sisimai::Bite::Email
|
|
249
236
|
# MAIL | Connected to 192.0.2.135 but sender was rejected.
|
250
237
|
e['reason'] = 'rejected'
|
251
238
|
|
252
|
-
elsif e['command']
|
239
|
+
elsif %w[HELO EHLO].index(e['command'])
|
253
240
|
# HELO | Connected to 192.0.2.135 but my name was rejected.
|
254
241
|
e['reason'] = 'blocked'
|
255
|
-
|
256
242
|
else
|
257
243
|
# Try to match with each error message in the table
|
258
|
-
if e['diagnosis'] =~
|
244
|
+
if e['diagnosis'] =~ ReIsOnHold
|
259
245
|
# To decide the reason require pattern match with
|
260
246
|
# Sisimai::Reason::* modules
|
261
247
|
e['reason'] = 'onhold'
|
262
|
-
|
263
248
|
else
|
264
|
-
|
249
|
+
ReFailures.each_key do |r|
|
265
250
|
# Verify each regular expression of session errors
|
266
251
|
if e['alterrors']
|
267
252
|
# Check the value of "alterrors"
|
268
|
-
next unless e['alterrors'] =~
|
253
|
+
next unless e['alterrors'] =~ ReFailures[r]
|
269
254
|
e['reason'] = r.to_s
|
270
255
|
end
|
271
256
|
break if e['reason']
|
272
257
|
|
273
|
-
next unless e['diagnosis'] =~
|
258
|
+
next unless e['diagnosis'] =~ ReFailures[r]
|
274
259
|
e['reason'] = r.to_s
|
275
260
|
break
|
276
261
|
end
|
@@ -285,7 +270,7 @@ module Sisimai::Bite::Email
|
|
285
270
|
end
|
286
271
|
|
287
272
|
unless e['reason']
|
288
|
-
e['reason'] = 'expired' if e['diagnosis'] =~
|
273
|
+
e['reason'] = 'expired' if e['diagnosis'] =~ ReDelaying
|
289
274
|
end
|
290
275
|
end
|
291
276
|
end
|
@@ -8,23 +8,18 @@ module Sisimai::Bite::Email
|
|
8
8
|
require 'sisimai/bite/email'
|
9
9
|
|
10
10
|
# http://aws.amazon.com/ses/
|
11
|
-
|
12
|
-
|
13
|
-
:
|
14
|
-
|
15
|
-
Re1 = {
|
16
|
-
:begin => %r/\AThis message could not be delivered[.]\z/,
|
17
|
-
:rfc822 => %r|\Acontent-type: text/rfc822-headers\z|,
|
18
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
11
|
+
Indicators = Sisimai::Bite::Email.INDICATORS
|
12
|
+
StartingOf = {
|
13
|
+
message: ['This message could not be delivered.'],
|
14
|
+
rfc822: ['content-type: text/rfc822-headers'],
|
19
15
|
}.freeze
|
20
|
-
|
16
|
+
ReFailures = {
|
21
17
|
# The followings are error messages in Rule sets/*/Actions/Template
|
22
18
|
filtered: %r/Mailbox does not exist/,
|
23
19
|
mesgtoobig: %r/Message too large/,
|
24
20
|
mailboxfull: %r/Mailbox full/,
|
25
21
|
contenterror: %r/Message content rejected/,
|
26
22
|
}.freeze
|
27
|
-
Indicators = Sisimai::Bite::Email.INDICATORS
|
28
23
|
|
29
24
|
def description; return 'Amazon SES(Receiving): http://aws.amazon.com/ses/'; end
|
30
25
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
@@ -32,7 +27,6 @@ module Sisimai::Bite::Email
|
|
32
27
|
# X-SES-Outgoing: 2015.10.01-54.240.27.7
|
33
28
|
# Feedback-ID: 1.us-west-2.HX6/J9OVlHTadQhEu1+wdF9DBj6n6Pa9sW5Y/0pSOi8=:AmazonSES
|
34
29
|
def headerlist; return ['X-SES-Outgoing']; end
|
35
|
-
def pattern; return Re0; end
|
36
30
|
|
37
31
|
# Parse bounce messages from Amazon SES/Receiving
|
38
32
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -48,6 +42,9 @@ module Sisimai::Bite::Email
|
|
48
42
|
def scan(mhead, mbody)
|
49
43
|
return nil unless mhead
|
50
44
|
return nil unless mbody
|
45
|
+
|
46
|
+
# :subject => %r/\ADelivery Status Notification [(]Failure[)]\z/,
|
47
|
+
# :received => %r/.+[.]smtp-out[.].+[.]amazonses[.]com\b/,
|
51
48
|
return nil unless mhead['x-ses-outgoing']
|
52
49
|
|
53
50
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
@@ -64,14 +61,14 @@ module Sisimai::Bite::Email
|
|
64
61
|
}
|
65
62
|
v = nil
|
66
63
|
|
67
|
-
hasdivided.
|
64
|
+
while e = hasdivided.shift do
|
68
65
|
# Save the current line for the next loop
|
69
66
|
havepassed << e
|
70
67
|
p = havepassed[-2]
|
71
68
|
|
72
69
|
if readcursor.zero?
|
73
70
|
# Beginning of the bounce message or delivery status part
|
74
|
-
if e
|
71
|
+
if e == StartingOf[:message][0]
|
75
72
|
readcursor |= Indicators[:deliverystatus]
|
76
73
|
next
|
77
74
|
end
|
@@ -79,7 +76,7 @@ module Sisimai::Bite::Email
|
|
79
76
|
|
80
77
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
81
78
|
# Beginning of the original message part
|
82
|
-
if e
|
79
|
+
if e == StartingOf[:rfc822][0]
|
83
80
|
readcursor |= Indicators[:'message-rfc822']
|
84
81
|
next
|
85
82
|
end
|
@@ -93,7 +90,6 @@ module Sisimai::Bite::Email
|
|
93
90
|
next
|
94
91
|
end
|
95
92
|
rfc822list << e
|
96
|
-
|
97
93
|
else
|
98
94
|
# Before "message/rfc822"
|
99
95
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -107,7 +103,7 @@ module Sisimai::Bite::Email
|
|
107
103
|
# Status: 5.1.1
|
108
104
|
v = dscontents[-1]
|
109
105
|
|
110
|
-
if cv = e.match(/\
|
106
|
+
if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
|
111
107
|
# Final-Recipient: RFC822; kijitora@example.jp
|
112
108
|
if v['recipient']
|
113
109
|
# There are multiple recipient addresses in the message body.
|
@@ -117,41 +113,38 @@ module Sisimai::Bite::Email
|
|
117
113
|
v['recipient'] = cv[1]
|
118
114
|
recipients += 1
|
119
115
|
|
120
|
-
elsif cv = e.match(/\
|
121
|
-
e.match(/\
|
116
|
+
elsif cv = e.match(/\AX-Actual-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/) ||
|
117
|
+
e.match(/\AOriginal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
|
122
118
|
# X-Actual-Recipient: RFC822; kijitora@example.co.jp
|
123
119
|
# Original-Recipient: rfc822; kijitora@example.co.jp
|
124
120
|
v['alias'] = cv[1]
|
125
121
|
|
126
|
-
elsif cv = e.match(/\
|
122
|
+
elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
|
127
123
|
# Action: failed
|
128
124
|
v['action'] = cv[1].downcase
|
129
125
|
|
130
|
-
elsif cv = e.match(/\
|
126
|
+
elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
|
131
127
|
# Status: 5.1.1
|
132
128
|
v['status'] = cv[1]
|
133
129
|
|
134
|
-
elsif cv = e.match(/\
|
130
|
+
elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
|
135
131
|
# Remote-MTA: DNS; mx.example.jp
|
136
132
|
v['rhost'] = cv[1].downcase
|
137
133
|
|
138
|
-
elsif cv = e.match(/\
|
134
|
+
elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
|
139
135
|
# Last-Attempt-Date: Fri, 14 Feb 2014 12:30:08 -0500
|
140
136
|
v['date'] = cv[1]
|
141
|
-
|
142
137
|
else
|
143
|
-
if cv = e.match(/\
|
138
|
+
if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
|
144
139
|
# Diagnostic-Code: SMTP; 550 5.1.1 <kijitora@example.jp>... User Unknown
|
145
140
|
v['spec'] = cv[1].upcase
|
146
141
|
v['diagnosis'] = cv[2]
|
147
142
|
|
148
|
-
elsif p
|
143
|
+
elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
|
149
144
|
# Continued line of the value of Diagnostic-Code header
|
150
|
-
v['diagnosis']
|
151
|
-
|
152
|
-
havepassed[-1] = 'Diagnostic-Code: ' + e
|
145
|
+
v['diagnosis'] << ' ' << cv[1]
|
146
|
+
havepassed[-1] = 'Diagnostic-Code: ' << e
|
153
147
|
end
|
154
|
-
|
155
148
|
end
|
156
149
|
else
|
157
150
|
# This message could not be delivered.
|
@@ -161,13 +154,13 @@ module Sisimai::Bite::Email
|
|
161
154
|
# Content-Description: Delivery Status Notification
|
162
155
|
#
|
163
156
|
# Reporting-MTA: dns; inbound-smtp.us-west-2.amazonaws.com
|
164
|
-
if cv = e.match(/\
|
157
|
+
if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
|
165
158
|
# Reporting-MTA: dns; mx.example.jp
|
166
159
|
next if connheader['lhost'].size > 0
|
167
160
|
connheader['lhost'] = cv[1].downcase
|
168
161
|
connvalues += 1
|
169
162
|
|
170
|
-
elsif cv = e.match(/\
|
163
|
+
elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
|
171
164
|
# Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
|
172
165
|
next if connheader['date'].size > 0
|
173
166
|
connheader['date'] = cv[1]
|
@@ -176,11 +169,10 @@ module Sisimai::Bite::Email
|
|
176
169
|
end
|
177
170
|
end
|
178
171
|
end
|
179
|
-
|
180
172
|
return nil if recipients.zero?
|
173
|
+
|
181
174
|
require 'sisimai/string'
|
182
175
|
require 'sisimai/smtp/status'
|
183
|
-
|
184
176
|
dscontents.map do |e|
|
185
177
|
# Set default values if each value is empty.
|
186
178
|
connheader.each_key { |a| e[a] ||= connheader[a] || '' }
|
@@ -188,7 +180,7 @@ module Sisimai::Bite::Email
|
|
188
180
|
e['diagnosis'] = e['diagnosis'].gsub(/\\n/, ' ')
|
189
181
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
190
182
|
|
191
|
-
if e['status']
|
183
|
+
if e['status'].to_s.start_with?('5.0.0', '5.1.0', '4.0.0', '4.1.0')
|
192
184
|
# Get other D.S.N. value from the error message
|
193
185
|
errormessage = e['diagnosis']
|
194
186
|
|
@@ -200,9 +192,9 @@ module Sisimai::Bite::Email
|
|
200
192
|
e['status'] = pseudostatus if pseudostatus.size > 0
|
201
193
|
end
|
202
194
|
|
203
|
-
|
195
|
+
ReFailures.each_key do |r|
|
204
196
|
# Verify each regular expression of session errors
|
205
|
-
next unless e['diagnosis'] =~
|
197
|
+
next unless e['diagnosis'] =~ ReFailures[r]
|
206
198
|
e['reason'] = r.to_s
|
207
199
|
break
|
208
200
|
end
|
@@ -6,18 +6,11 @@ module Sisimai::Bite::Email
|
|
6
6
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/SendGrid.pm
|
7
7
|
require 'sisimai/bite/email'
|
8
8
|
|
9
|
-
Re0 = {
|
10
|
-
:'from' => %r/\AMAILER-DAEMON\z/,
|
11
|
-
:'return-path' => %r/\A[<]apps[@]sendgrid[.]net[>]\z/,
|
12
|
-
:'subject' => %r/\AUndelivered Mail Returned to Sender\z/,
|
13
|
-
}.freeze
|
14
|
-
Re1 = {
|
15
|
-
:begin => %r/\AThis is an automatically generated message from SendGrid[.]\z/,
|
16
|
-
:error => %r/\AIf you require assistance with this, please contact SendGrid support[.]\z/,
|
17
|
-
:rfc822 => %r|\AContent-Type: message/rfc822|,
|
18
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
19
|
-
}.freeze
|
20
9
|
Indicators = Sisimai::Bite::Email.INDICATORS
|
10
|
+
StartingOf = {
|
11
|
+
message: ['This is an automatically generated message from SendGrid.'],
|
12
|
+
rfc822: ['Content-Type: message/rfc822'],
|
13
|
+
}.freeze
|
21
14
|
|
22
15
|
def description; return 'SendGrid: http://sendgrid.com/'; end
|
23
16
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
@@ -25,7 +18,6 @@ module Sisimai::Bite::Email
|
|
25
18
|
# Return-Path: <apps@sendgrid.net>
|
26
19
|
# X-Mailer: MIME-tools 5.502 (Entity 5.502)
|
27
20
|
def headerlist; return ['Return-Path', 'X-Mailer']; end
|
28
|
-
def pattern; return Re0; end
|
29
21
|
|
30
22
|
# Parse bounce messages from SendGrid
|
31
23
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -41,9 +33,11 @@ module Sisimai::Bite::Email
|
|
41
33
|
def scan(mhead, mbody)
|
42
34
|
return nil unless mhead
|
43
35
|
return nil unless mbody
|
36
|
+
|
37
|
+
# :'from' => %r/\AMAILER-DAEMON\z/,
|
44
38
|
return nil unless mhead['return-path']
|
45
|
-
return nil unless mhead['return-path']
|
46
|
-
return nil unless mhead['subject']
|
39
|
+
return nil unless mhead['return-path'] == '<apps@sendgrid.net>'
|
40
|
+
return nil unless mhead['subject'] == 'Undelivered Mail Returned to Sender'
|
47
41
|
|
48
42
|
require 'sisimai/datetime'
|
49
43
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
@@ -60,14 +54,14 @@ module Sisimai::Bite::Email
|
|
60
54
|
}
|
61
55
|
v = nil
|
62
56
|
|
63
|
-
hasdivided.
|
57
|
+
while e = hasdivided.shift do
|
64
58
|
# Save the current line for the next loop
|
65
59
|
havepassed << e
|
66
60
|
p = havepassed[-2]
|
67
61
|
|
68
62
|
if readcursor.zero?
|
69
63
|
# Beginning of the bounce message or delivery status part
|
70
|
-
if e
|
64
|
+
if e == StartingOf[:message][0]
|
71
65
|
readcursor |= Indicators[:deliverystatus]
|
72
66
|
next
|
73
67
|
end
|
@@ -75,7 +69,7 @@ module Sisimai::Bite::Email
|
|
75
69
|
|
76
70
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
77
71
|
# Beginning of the original message part
|
78
|
-
if e
|
72
|
+
if e == StartingOf[:rfc822][0]
|
79
73
|
readcursor |= Indicators[:'message-rfc822']
|
80
74
|
next
|
81
75
|
end
|
@@ -89,7 +83,6 @@ module Sisimai::Bite::Email
|
|
89
83
|
next
|
90
84
|
end
|
91
85
|
rfc822list << e
|
92
|
-
|
93
86
|
else
|
94
87
|
# Before "message/rfc822"
|
95
88
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -103,7 +96,7 @@ module Sisimai::Bite::Email
|
|
103
96
|
# Diagnostic-Code: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
104
97
|
v = dscontents[-1]
|
105
98
|
|
106
|
-
if cv = e.match(/\
|
99
|
+
if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
|
107
100
|
# Final-Recipient: RFC822; userunknown@example.jp
|
108
101
|
if v['recipient']
|
109
102
|
# There are multiple recipient addresses in the message body.
|
@@ -113,26 +106,25 @@ module Sisimai::Bite::Email
|
|
113
106
|
v['recipient'] = cv[1]
|
114
107
|
recipients += 1
|
115
108
|
|
116
|
-
elsif cv = e.match(/\
|
109
|
+
elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
|
117
110
|
# Action: failed
|
118
111
|
v['action'] = cv[1].downcase
|
119
112
|
|
120
|
-
elsif cv = e.match(/\
|
113
|
+
elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
|
121
114
|
# Status: 5.1.1
|
122
115
|
# Status:5.2.0
|
123
116
|
# Status: 5.1.0 (permanent failure)
|
124
117
|
v['status'] = cv[1]
|
125
118
|
|
126
119
|
else
|
127
|
-
if cv = e.match(/\
|
120
|
+
if cv = e.match(/\ADiagnostic-Code:[ ]*(.+)\z/)
|
128
121
|
# Diagnostic-Code: 550 5.1.1 <userunknown@example.jp>... User Unknown
|
129
122
|
v['diagnosis'] = cv[1]
|
130
123
|
|
131
|
-
elsif p
|
124
|
+
elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
|
132
125
|
# Continued line of the value of Diagnostic-Code header
|
133
|
-
v['diagnosis']
|
134
|
-
|
135
|
-
havepassed[-1] = 'Diagnostic-Code: ' + e
|
126
|
+
v['diagnosis'] << ' ' << cv[1]
|
127
|
+
havepassed[-1] = 'Diagnostic-Code: ' << e
|
136
128
|
end
|
137
129
|
end
|
138
130
|
else
|
@@ -159,17 +151,17 @@ module Sisimai::Bite::Email
|
|
159
151
|
# in RCPT TO, in MAIL FROM, end of DATA
|
160
152
|
commandtxt = cv[1]
|
161
153
|
|
162
|
-
elsif cv = e.match(/\
|
154
|
+
elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
|
163
155
|
# Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
|
164
156
|
next if connheader['date'].size > 0
|
165
157
|
arrivaldate = cv[1]
|
166
158
|
|
167
|
-
if cv = e.match(/\
|
159
|
+
if cv = e.match(/\AArrival-Date: (\d{4})[-](\d{2})[-](\d{2}) (\d{2})[-](\d{2})[-](\d{2})\z/)
|
168
160
|
# Arrival-Date: 2011-08-12 01-05-05
|
169
|
-
arrivaldate
|
170
|
-
arrivaldate
|
171
|
-
arrivaldate
|
172
|
-
arrivaldate
|
161
|
+
arrivaldate << 'Thu, ' << cv[3] + ' '
|
162
|
+
arrivaldate << Sisimai::DateTime.monthname(0)[cv[2].to_i - 1]
|
163
|
+
arrivaldate << ' ' << cv[1] + ' ' << [cv[4], cv[5], cv[6]].join(':')
|
164
|
+
arrivaldate << ' ' << Sisimai::DateTime.abbr2tz('CDT')
|
173
165
|
end
|
174
166
|
connheader['date'] = arrivaldate
|
175
167
|
connvalues += 1
|
@@ -177,21 +169,20 @@ module Sisimai::Bite::Email
|
|
177
169
|
end
|
178
170
|
end
|
179
171
|
end
|
180
|
-
|
181
172
|
return nil if recipients.zero?
|
173
|
+
|
182
174
|
require 'sisimai/string'
|
183
175
|
require 'sisimai/smtp/status'
|
184
|
-
|
185
176
|
dscontents.map do |e|
|
186
177
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
187
178
|
|
188
179
|
# Get the value of SMTP status code as a pseudo D.S.N.
|
189
180
|
if cv = e['diagnosis'].match(/\b([45])\d\d[ \t]*/)
|
190
181
|
# 4xx or 5xx
|
191
|
-
e['status'] =
|
182
|
+
e['status'] = cv[1] + '.0.0'
|
192
183
|
end
|
193
184
|
|
194
|
-
if e['status']
|
185
|
+
if e['status'] == '5.0.0' || e['status'] == '4.0.0'
|
195
186
|
# Get the value of D.S.N. from the error message or the value of
|
196
187
|
# Diagnostic-Code header.
|
197
188
|
pseudostatus = Sisimai::SMTP::Status.find(e['diagnosis'])
|
@@ -201,7 +192,7 @@ module Sisimai::Bite::Email
|
|
201
192
|
if e['action'] == 'expired'
|
202
193
|
# Action: expired
|
203
194
|
e['reason'] = 'expired'
|
204
|
-
if !e['status'] || e['status']
|
195
|
+
if !e['status'] || e['status'].end_with?('.0.0')
|
205
196
|
# Set pseudo Status code value if the value of Status is not
|
206
197
|
# defined or 4.0.0 or 5.0.0.
|
207
198
|
pseudostatus = Sisimai::SMTP::Status.code('expired')
|