sisimai 4.25.4 → 4.25.5
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 +2 -2
- data/ChangeLog.md +50 -0
- data/README-JA.md +10 -37
- data/README.md +10 -37
- data/lib/sisimai.rb +15 -64
- data/lib/sisimai/address.rb +13 -17
- data/lib/sisimai/arf.rb +4 -4
- data/lib/sisimai/data.rb +3 -5
- data/lib/sisimai/lhost.rb +0 -14
- data/lib/sisimai/lhost/activehunter.rb +31 -55
- data/lib/sisimai/lhost/amavis.rb +41 -66
- data/lib/sisimai/lhost/amazonses.rb +189 -235
- data/lib/sisimai/lhost/amazonworkmail.rb +48 -71
- data/lib/sisimai/lhost/aol.rb +49 -75
- data/lib/sisimai/lhost/apachejames.rb +60 -83
- data/lib/sisimai/lhost/bigfoot.rb +61 -85
- data/lib/sisimai/lhost/biglobe.rb +40 -62
- data/lib/sisimai/lhost/courier.rb +60 -82
- data/lib/sisimai/lhost/domino.rb +50 -76
- data/lib/sisimai/lhost/einsundeins.rb +57 -55
- data/lib/sisimai/lhost/exchange2003.rb +79 -101
- data/lib/sisimai/lhost/exchange2007.rb +66 -74
- data/lib/sisimai/lhost/exim.rb +119 -142
- data/lib/sisimai/lhost/ezweb.rb +53 -73
- data/lib/sisimai/lhost/facebook.rb +49 -75
- data/lib/sisimai/lhost/fml.rb +25 -50
- data/lib/sisimai/lhost/gmx.rb +55 -79
- data/lib/sisimai/lhost/google.rb +39 -66
- data/lib/sisimai/lhost/gsuite.rb +74 -94
- data/lib/sisimai/lhost/imailserver.rb +34 -67
- data/lib/sisimai/lhost/interscanmss.rb +33 -67
- data/lib/sisimai/lhost/kddi.rb +30 -52
- data/lib/sisimai/lhost/mailfoundry.rb +35 -57
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +66 -89
- data/lib/sisimai/lhost/mailru.rb +51 -76
- data/lib/sisimai/lhost/mcafee.rb +53 -79
- data/lib/sisimai/lhost/messagelabs.rb +49 -75
- data/lib/sisimai/lhost/messagingserver.rb +91 -113
- data/lib/sisimai/lhost/mfilter.rb +50 -70
- data/lib/sisimai/lhost/mxlogic.rb +38 -63
- data/lib/sisimai/lhost/notes.rb +53 -82
- data/lib/sisimai/lhost/office365.rb +64 -81
- data/lib/sisimai/lhost/opensmtpd.rb +30 -52
- data/lib/sisimai/lhost/outlook.rb +49 -75
- data/lib/sisimai/lhost/postfix.rb +116 -117
- data/lib/sisimai/lhost/qmail.rb +33 -55
- data/lib/sisimai/lhost/receivingses.rb +49 -75
- data/lib/sisimai/lhost/sendgrid.rb +68 -203
- data/lib/sisimai/lhost/sendmail.rb +101 -125
- data/lib/sisimai/lhost/surfcontrol.rb +53 -79
- data/lib/sisimai/lhost/userdefined.rb +15 -35
- data/lib/sisimai/lhost/v5sendmail.rb +59 -89
- data/lib/sisimai/lhost/verizon.rb +75 -124
- data/lib/sisimai/lhost/x1.rb +30 -54
- data/lib/sisimai/lhost/x2.rb +28 -52
- data/lib/sisimai/lhost/x3.rb +44 -68
- data/lib/sisimai/lhost/x4.rb +34 -58
- data/lib/sisimai/lhost/x5.rb +42 -70
- data/lib/sisimai/lhost/yahoo.rb +44 -68
- data/lib/sisimai/lhost/yandex.rb +59 -85
- data/lib/sisimai/lhost/zoho.rb +54 -78
- data/lib/sisimai/mail.rb +5 -9
- data/lib/sisimai/mail/maildir.rb +10 -14
- data/lib/sisimai/mail/mbox.rb +8 -12
- data/lib/sisimai/mail/memory.rb +5 -9
- data/lib/sisimai/mail/stdin.rb +7 -11
- data/lib/sisimai/mda.rb +2 -2
- data/lib/sisimai/message.rb +51 -154
- data/lib/sisimai/mime.rb +2 -2
- data/lib/sisimai/order.rb +2 -27
- data/lib/sisimai/reason.rb +3 -5
- data/lib/sisimai/rfc1894.rb +1 -1
- data/lib/sisimai/rfc3464.rb +29 -29
- data/lib/sisimai/rfc3834.rb +7 -6
- data/lib/sisimai/rfc5322.rb +20 -31
- data/lib/sisimai/rhost/franceptt.rb +120 -24
- data/lib/sisimai/rhost/iua.rb +1 -1
- data/lib/sisimai/smtp/error.rb +7 -7
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/maildir/bsd/email-einsundeins-03.eml +66 -0
- data/set-of-emails/maildir/bsd/email-exchange2007-05.eml +1469 -0
- data/set-of-emails/maildir/bsd/email-exchange2007-06.eml +764 -0
- data/set-of-emails/maildir/bsd/email-postfix-64.eml +96 -0
- data/set-of-emails/maildir/bsd/rfc3834-03.eml +26 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-04.eml +66 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-05.eml +96 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-06.eml +100 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-07.eml +97 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-08.eml +78 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-10.eml +79 -0
- data/set-of-emails/maildir/bsd/rhost-franceptt-11.eml +96 -0
- metadata +14 -9
- data/lib/sisimai/bite.rb +0 -42
- data/lib/sisimai/bite/email.rb +0 -18
- data/lib/sisimai/bite/json.rb +0 -16
- data/lib/sisimai/message/email.rb +0 -26
- data/lib/sisimai/message/json.rb +0 -24
- data/lib/sisimai/order/email.rb +0 -20
- data/lib/sisimai/order/json.rb +0 -16
data/lib/sisimai/lhost/qmail.rb
CHANGED
@@ -7,6 +7,7 @@ module Sisimai::Lhost
|
|
7
7
|
require 'sisimai/lhost'
|
8
8
|
|
9
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
+
ReBackbone = %r|^--- Below this line is a copy of the message[.]|.freeze
|
10
11
|
StartingOf = {
|
11
12
|
# qmail-remote.c:248| if (code >= 500) {
|
12
13
|
# qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
|
@@ -16,7 +17,6 @@ module Sisimai::Lhost
|
|
16
17
|
# Characters: K,Z,D in qmail-qmqpc.c, qmail-send.c, qmail-rspawn.c
|
17
18
|
# K = success, Z = temporary error, D = permanent error
|
18
19
|
message: ['Hi. This is the qmail'],
|
19
|
-
rfc822: ['--- Below this line is a copy of the message.'],
|
20
20
|
error: ['Remote host said:'],
|
21
21
|
}.freeze
|
22
22
|
|
@@ -126,70 +126,49 @@ module Sisimai::Lhost
|
|
126
126
|
return nil unless match > 0
|
127
127
|
|
128
128
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
129
|
-
|
130
|
-
|
131
|
-
blanklines = 0 # (Integer) The number of blank lines
|
129
|
+
emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
|
130
|
+
bodyslices = emailsteak[0].split("\n")
|
132
131
|
readcursor = 0 # (Integer) Points the current cursor position
|
133
132
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
134
133
|
v = nil
|
135
134
|
|
136
|
-
while e =
|
135
|
+
while e = bodyslices.shift do
|
136
|
+
# Read error messages and delivery status lines from the head of the email
|
137
|
+
# to the previous line of the beginning of the original message.
|
137
138
|
if readcursor == 0
|
138
139
|
# Beginning of the bounce message or delivery status part
|
139
|
-
if e.start_with?(StartingOf[:message][0])
|
140
|
-
|
141
|
-
next
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
if (readcursor & Indicators[:'message-rfc822']) == 0
|
146
|
-
# Beginning of the original message part
|
147
|
-
if e == StartingOf[:rfc822][0]
|
148
|
-
readcursor |= Indicators[:'message-rfc822']
|
149
|
-
next
|
150
|
-
end
|
140
|
+
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
141
|
+
next
|
151
142
|
end
|
143
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0
|
144
|
+
next if e.empty?
|
152
145
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
next
|
159
|
-
end
|
160
|
-
rfc822list << e
|
161
|
-
else
|
162
|
-
# Error message part
|
163
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
164
|
-
next if e.empty?
|
146
|
+
# <kijitora@example.jp>:
|
147
|
+
# 192.0.2.153 does not like recipient.
|
148
|
+
# Remote host said: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
149
|
+
# Giving up on 192.0.2.153.
|
150
|
+
v = dscontents[-1]
|
165
151
|
|
152
|
+
if cv = e.match(/\A(?:To[ ]*:)?[<](.+[@].+)[>]:[ \t]*\z/)
|
166
153
|
# <kijitora@example.jp>:
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
if v['recipient']
|
175
|
-
# There are multiple recipient addresses in the message body.
|
176
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
177
|
-
v = dscontents[-1]
|
178
|
-
end
|
179
|
-
v['recipient'] = cv[1]
|
180
|
-
recipients += 1
|
154
|
+
if v['recipient']
|
155
|
+
# There are multiple recipient addresses in the message body.
|
156
|
+
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
157
|
+
v = dscontents[-1]
|
158
|
+
end
|
159
|
+
v['recipient'] = cv[1]
|
160
|
+
recipients += 1
|
181
161
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
162
|
+
elsif dscontents.size == recipients
|
163
|
+
# Append error message
|
164
|
+
next if e.empty?
|
165
|
+
v['diagnosis'] ||= ''
|
166
|
+
v['diagnosis'] << e + ' '
|
167
|
+
v['alterrors'] = e if e.start_with?(StartingOf[:error][0])
|
188
168
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
169
|
+
next if v['rhost']
|
170
|
+
next unless cv = e.match(ReHost)
|
171
|
+
v['rhost'] = cv[1]
|
193
172
|
end
|
194
173
|
end
|
195
174
|
return nil unless recipients > 0
|
@@ -262,8 +241,7 @@ module Sisimai::Lhost
|
|
262
241
|
e.each_key { |a| e[a] ||= '' }
|
263
242
|
end
|
264
243
|
|
265
|
-
|
266
|
-
return { 'ds' => dscontents, 'rfc822' => rfc822part }
|
244
|
+
return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
|
267
245
|
end
|
268
246
|
|
269
247
|
end
|
@@ -9,10 +9,8 @@ module Sisimai::Lhost
|
|
9
9
|
|
10
10
|
# https://aws.amazon.com/ses/
|
11
11
|
Indicators = Sisimai::Lhost.INDICATORS
|
12
|
-
|
13
|
-
|
14
|
-
rfc822: ['content-type: text/rfc822-headers'],
|
15
|
-
}.freeze
|
12
|
+
ReBackbone = %r|^content-type:[ ]text/rfc822-headers|.freeze
|
13
|
+
StartingOf = { message: ['This message could not be delivered.'] }.freeze
|
16
14
|
MessagesOf = {
|
17
15
|
# The followings are error messages in Rule sets/*/Actions/Template
|
18
16
|
'filtered' => ['Mailbox does not exist'],
|
@@ -49,89 +47,66 @@ module Sisimai::Lhost
|
|
49
47
|
permessage = {} # (Hash) Store values of each Per-Message field
|
50
48
|
|
51
49
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
blanklines = 0 # (Integer) The number of blank lines
|
50
|
+
emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
|
51
|
+
bodyslices = emailsteak[0].split("\n")
|
52
|
+
readslices = ['']
|
56
53
|
readcursor = 0 # (Integer) Points the current cursor position
|
57
54
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
58
55
|
v = nil
|
59
56
|
|
60
|
-
while e =
|
61
|
-
#
|
62
|
-
|
63
|
-
|
57
|
+
while e = bodyslices.shift do
|
58
|
+
# Read error messages and delivery status lines from the head of the email
|
59
|
+
# to the previous line of the beginning of the original message.
|
60
|
+
readslices << e # Save the current line for the next loop
|
64
61
|
|
65
62
|
if readcursor == 0
|
66
63
|
# Beginning of the bounce message or message/delivery-status part
|
67
|
-
if e == StartingOf[:message][0]
|
68
|
-
|
69
|
-
next
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
if (readcursor & Indicators[:'message-rfc822']) == 0
|
74
|
-
# Beginning of the original message part(message/rfc822)
|
75
|
-
if e == StartingOf[:rfc822][0]
|
76
|
-
readcursor |= Indicators[:'message-rfc822']
|
77
|
-
next
|
78
|
-
end
|
64
|
+
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
65
|
+
next
|
79
66
|
end
|
80
|
-
|
81
|
-
if
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
next if e.empty?
|
93
|
-
|
94
|
-
if f = Sisimai::RFC1894.match(e)
|
95
|
-
# "e" matched with any field defined in RFC3464
|
96
|
-
next unless o = Sisimai::RFC1894.field(e)
|
97
|
-
v = dscontents[-1]
|
98
|
-
|
99
|
-
if o[-1] == 'addr'
|
67
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0
|
68
|
+
next if e.empty?
|
69
|
+
|
70
|
+
if f = Sisimai::RFC1894.match(e)
|
71
|
+
# "e" matched with any field defined in RFC3464
|
72
|
+
next unless o = Sisimai::RFC1894.field(e)
|
73
|
+
v = dscontents[-1]
|
74
|
+
|
75
|
+
if o[-1] == 'addr'
|
76
|
+
# Final-Recipient: rfc822; kijitora@example.jp
|
77
|
+
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
78
|
+
if o[0] == 'final-recipient'
|
100
79
|
# Final-Recipient: rfc822; kijitora@example.jp
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
# There are multiple recipient addresses in the message body.
|
106
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
107
|
-
v = dscontents[-1]
|
108
|
-
end
|
109
|
-
v['recipient'] = o[2]
|
110
|
-
recipients += 1
|
111
|
-
else
|
112
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
113
|
-
v['alias'] = o[2]
|
80
|
+
if v['recipient']
|
81
|
+
# There are multiple recipient addresses in the message body.
|
82
|
+
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
83
|
+
v = dscontents[-1]
|
114
84
|
end
|
115
|
-
|
116
|
-
|
117
|
-
v['spec'] = o[1]
|
118
|
-
v['diagnosis'] = o[2]
|
85
|
+
v['recipient'] = o[2]
|
86
|
+
recipients += 1
|
119
87
|
else
|
120
|
-
#
|
121
|
-
|
122
|
-
v[fieldtable[o[0]]] = o[2]
|
123
|
-
|
124
|
-
next unless f == 1
|
125
|
-
permessage[fieldtable[o[0]]] = o[2]
|
88
|
+
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
89
|
+
v['alias'] = o[2]
|
126
90
|
end
|
91
|
+
elsif o[-1] == 'code'
|
92
|
+
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
93
|
+
v['spec'] = o[1]
|
94
|
+
v['diagnosis'] = o[2]
|
127
95
|
else
|
128
|
-
#
|
129
|
-
next unless
|
130
|
-
|
131
|
-
|
132
|
-
|
96
|
+
# Other DSN fields defined in RFC3464
|
97
|
+
next unless fieldtable[o[0]]
|
98
|
+
v[fieldtable[o[0]]] = o[2]
|
99
|
+
|
100
|
+
next unless f == 1
|
101
|
+
permessage[fieldtable[o[0]]] = o[2]
|
133
102
|
end
|
134
|
-
|
103
|
+
else
|
104
|
+
# Continued line of the value of Diagnostic-Code field
|
105
|
+
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
106
|
+
next unless cv = e.match(/\A[ \t]+(.+)\z/)
|
107
|
+
v['diagnosis'] << ' ' << cv[1]
|
108
|
+
readslices[-1] = 'Diagnostic-Code: ' << e
|
109
|
+
end
|
135
110
|
end
|
136
111
|
return nil unless recipients > 0
|
137
112
|
|
@@ -163,8 +138,7 @@ module Sisimai::Lhost
|
|
163
138
|
e['agent'] = self.smtpagent
|
164
139
|
end
|
165
140
|
|
166
|
-
|
167
|
-
return { 'ds' => dscontents, 'rfc822' => rfc822part }
|
141
|
+
return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
|
168
142
|
end
|
169
143
|
|
170
144
|
end
|
@@ -7,10 +7,8 @@ module Sisimai::Lhost
|
|
7
7
|
require 'sisimai/lhost'
|
8
8
|
|
9
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
11
|
-
|
12
|
-
rfc822: ['Content-Type: message/rfc822'],
|
13
|
-
}.freeze
|
10
|
+
ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
|
11
|
+
StartingOf = { message: ['This is an automatically generated message from SendGrid.'] }.freeze
|
14
12
|
|
15
13
|
def description; return 'SendGrid: https://sendgrid.com/'; end
|
16
14
|
def smtpagent; return Sisimai::Lhost.smtpagent(self); end
|
@@ -41,112 +39,89 @@ module Sisimai::Lhost
|
|
41
39
|
permessage = {} # (Hash) Store values of each Per-Message field
|
42
40
|
|
43
41
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
blanklines = 0 # (Integer) The number of blank lines
|
42
|
+
emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
|
43
|
+
bodyslices = emailsteak[0].split("\n")
|
44
|
+
readslices = ['']
|
48
45
|
readcursor = 0 # (Integer) Points the current cursor position
|
49
46
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
50
47
|
commandtxt = '' # (String) SMTP Command name begin with the string '>>>'
|
51
48
|
v = nil
|
52
49
|
|
53
|
-
while e =
|
54
|
-
#
|
55
|
-
|
56
|
-
|
50
|
+
while e = bodyslices.shift do
|
51
|
+
# Read error messages and delivery status lines from the head of the email
|
52
|
+
# to the previous line of the beginning of the original message.
|
53
|
+
readslices << e # Save the current line for the next loop
|
57
54
|
|
58
55
|
if readcursor == 0
|
59
56
|
# Beginning of the bounce message or message/delivery-status part
|
60
|
-
if e == StartingOf[:message][0]
|
61
|
-
|
62
|
-
next
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
if (readcursor & Indicators[:'message-rfc822']) == 0
|
67
|
-
# Beginning of the original message part(message/rfc822)
|
68
|
-
if e == StartingOf[:rfc822][0]
|
69
|
-
readcursor |= Indicators[:'message-rfc822']
|
70
|
-
next
|
71
|
-
end
|
57
|
+
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
58
|
+
next
|
72
59
|
end
|
73
|
-
|
74
|
-
if
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
60
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0
|
61
|
+
next if e.empty?
|
62
|
+
|
63
|
+
if f = Sisimai::RFC1894.match(e)
|
64
|
+
# "e" matched with any field defined in RFC3464
|
65
|
+
o = Sisimai::RFC1894.field(e)
|
66
|
+
v = dscontents[-1]
|
67
|
+
|
68
|
+
unless o
|
69
|
+
# Fallback code for empty value or invalid formatted value
|
70
|
+
# - Status: (empty)
|
71
|
+
# - Diagnostic-Code: 550 5.1.1 ... (No "diagnostic-type" sub field)
|
72
|
+
next unless cv = e.match(/\ADiagnostic-Code:[ ]*(.+)/)
|
73
|
+
v['diagnosis'] = cv[1]
|
79
74
|
next
|
80
75
|
end
|
81
|
-
rfc822list << e
|
82
|
-
else
|
83
|
-
# message/delivery-status part
|
84
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
85
|
-
next if e.empty?
|
86
76
|
|
87
|
-
if
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
unless o
|
93
|
-
# Fallback code for empty value or invalid formatted value
|
94
|
-
# - Status: (empty)
|
95
|
-
# - Diagnostic-Code: 550 5.1.1 ... (No "diagnostic-type" sub field)
|
96
|
-
next unless cv = e.match(/\ADiagnostic-Code:[ ]*(.+)/)
|
97
|
-
v['diagnosis'] = cv[1]
|
98
|
-
next
|
99
|
-
end
|
100
|
-
|
101
|
-
if o[-1] == 'addr'
|
77
|
+
if o[-1] == 'addr'
|
78
|
+
# Final-Recipient: rfc822; kijitora@example.jp
|
79
|
+
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
80
|
+
if o[0] == 'final-recipient'
|
102
81
|
# Final-Recipient: rfc822; kijitora@example.jp
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
# There are multiple recipient addresses in the message body.
|
108
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
109
|
-
v = dscontents[-1]
|
110
|
-
end
|
111
|
-
v['recipient'] = o[2]
|
112
|
-
recipients += 1
|
113
|
-
else
|
114
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
115
|
-
v['alias'] = o[2]
|
82
|
+
if v['recipient']
|
83
|
+
# There are multiple recipient addresses in the message body.
|
84
|
+
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
85
|
+
v = dscontents[-1]
|
116
86
|
end
|
117
|
-
|
118
|
-
|
119
|
-
v['spec'] = o[1]
|
120
|
-
v['diagnosis'] = o[2]
|
121
|
-
elsif o[-1] == 'date'
|
122
|
-
# Arrival-Date: 2012-12-31 23-59-59
|
123
|
-
next unless cv = e.match(/\AArrival-Date: (\d{4})[-](\d{2})[-](\d{2}) (\d{2})[-](\d{2})[-](\d{2})\z/)
|
124
|
-
o[1] << 'Thu, ' << cv[3] + ' '
|
125
|
-
o[1] << Sisimai::DateTime.monthname(0)[cv[2].to_i - 1]
|
126
|
-
o[1] << ' ' << cv[1] + ' ' << [cv[4], cv[5], cv[6]].join(':')
|
127
|
-
o[1] << ' ' << Sisimai::DateTime.abbr2tz('CDT')
|
87
|
+
v['recipient'] = o[2]
|
88
|
+
recipients += 1
|
128
89
|
else
|
129
|
-
#
|
130
|
-
|
131
|
-
v[fieldtable[o[0]]] = o[2]
|
132
|
-
|
133
|
-
next unless f == 1
|
134
|
-
permessage[fieldtable[o[0]]] = o[2]
|
90
|
+
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
91
|
+
v['alias'] = o[2]
|
135
92
|
end
|
93
|
+
elsif o[-1] == 'code'
|
94
|
+
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
95
|
+
v['spec'] = o[1]
|
96
|
+
v['diagnosis'] = o[2]
|
97
|
+
elsif o[-1] == 'date'
|
98
|
+
# Arrival-Date: 2012-12-31 23-59-59
|
99
|
+
next unless cv = e.match(/\AArrival-Date: (\d{4})[-](\d{2})[-](\d{2}) (\d{2})[-](\d{2})[-](\d{2})\z/)
|
100
|
+
o[1] << 'Thu, ' << cv[3] + ' '
|
101
|
+
o[1] << Sisimai::DateTime.monthname(0)[cv[2].to_i - 1]
|
102
|
+
o[1] << ' ' << cv[1] + ' ' << [cv[4], cv[5], cv[6]].join(':')
|
103
|
+
o[1] << ' ' << Sisimai::DateTime.abbr2tz('CDT')
|
136
104
|
else
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
105
|
+
# Other DSN fields defined in RFC3464
|
106
|
+
next unless fieldtable[o[0]]
|
107
|
+
v[fieldtable[o[0]]] = o[2]
|
108
|
+
|
109
|
+
next unless f == 1
|
110
|
+
permessage[fieldtable[o[0]]] = o[2]
|
111
|
+
end
|
112
|
+
else
|
113
|
+
# The line does not begin with a DSN field defined in RFC3464
|
114
|
+
if cv = e.match(/.+ in (?:End of )?([A-Z]{4}).*\z/)
|
115
|
+
# in RCPT TO, in MAIL FROM, end of DATA
|
116
|
+
commandtxt = cv[1]
|
117
|
+
else
|
118
|
+
# Continued line of the value of Diagnostic-Code field
|
119
|
+
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
120
|
+
next unless cv = e.match(/\A[ \t]+(.+)\z/)
|
121
|
+
v['diagnosis'] << ' ' << cv[1]
|
122
|
+
readslices[-1] = 'Diagnostic-Code: ' << e
|
148
123
|
end
|
149
|
-
end
|
124
|
+
end
|
150
125
|
end
|
151
126
|
return nil unless recipients > 0
|
152
127
|
|
@@ -179,117 +154,7 @@ module Sisimai::Lhost
|
|
179
154
|
e['command'] = commandtxt
|
180
155
|
end
|
181
156
|
|
182
|
-
|
183
|
-
return { 'ds' => dscontents, 'rfc822' => rfc822part }
|
184
|
-
end
|
185
|
-
|
186
|
-
# @abstract Adapt SendGrid bounce object for Sisimai::Message format
|
187
|
-
# @param [Hash] argvs bounce object(JSON) retrieved from SendGrid API
|
188
|
-
# @return [Hash, Nil] Bounce data list and message/rfc822 part or
|
189
|
-
# nil if it failed to parse or the
|
190
|
-
# arguments are missing
|
191
|
-
# @since v4.20.0
|
192
|
-
# @until v4.25.5
|
193
|
-
def json(argvs)
|
194
|
-
return nil unless argvs.is_a? Hash
|
195
|
-
return nil if argvs.empty?
|
196
|
-
return nil unless argvs.key?('email')
|
197
|
-
return nil unless Sisimai::RFC5322.is_emailaddress(argvs['email'])
|
198
|
-
|
199
|
-
dscontents = nil
|
200
|
-
rfc822head = {}
|
201
|
-
v = nil
|
202
|
-
|
203
|
-
if argvs.key?('event')
|
204
|
-
# https://sendgrid.com/docs/API_Reference/Webhooks/event.html
|
205
|
-
# {
|
206
|
-
# 'tls' => 0,
|
207
|
-
# 'timestamp' => 1504555832,
|
208
|
-
# 'event' => 'bounce',
|
209
|
-
# 'email' => 'mailboxfull@example.jp',
|
210
|
-
# 'ip' => '192.0.2.22',
|
211
|
-
# 'sg_message_id' => '03_Wof6nRbqqzxRvLpZbfw.filter0017p3mdw1-11399-59ADB335-16.0',
|
212
|
-
# 'type' => 'blocked',
|
213
|
-
# 'sg_event_id' => 'S4wr46YHS0qr3BKhawTQjQ',
|
214
|
-
# 'reason' => '550 5.2.2 <mailboxfull@example.jp>... Mailbox Full ',
|
215
|
-
# 'smtp-id' => '<201709042010.v84KAQ5T032530@example.nyaan.jp>',
|
216
|
-
# 'status' => '5.2.2'
|
217
|
-
# },
|
218
|
-
return nil unless %w[bounce deferred delivered spamreport].include?(argvs['event'])
|
219
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
220
|
-
diagnostic = argvs['reason'] || ''
|
221
|
-
diagnostic = argvs['response'] || '' if diagnostic.empty?
|
222
|
-
timestamp0 = Sisimai::Time.parse(::Time.at(argvs['timestamp']).to_s)
|
223
|
-
v = dscontents[-1]
|
224
|
-
|
225
|
-
v['date'] = timestamp0.strftime("%a, %d %b %Y %T %z")
|
226
|
-
v['agent'] = self.smtpagent
|
227
|
-
v['lhost'] = argvs['ip'] || ''
|
228
|
-
v['status'] = argvs['status'] || nil
|
229
|
-
v['diagnosis'] = Sisimai::String.sweep(diagnostic)
|
230
|
-
v['recipient'] = argvs['email']
|
231
|
-
|
232
|
-
if argvs['event'] == 'delivered'
|
233
|
-
# "event": "delivered"
|
234
|
-
v['reason'] = 'delivered'
|
235
|
-
elsif argvs['event'] == 'spamreport'
|
236
|
-
# [
|
237
|
-
# {
|
238
|
-
# "email": "kijitora@example.com",
|
239
|
-
# "timestamp": 1504837383,
|
240
|
-
# "sg_message_id": "6_hrAeKvTDaB5ynBI2nbnQ.filter0002p3las1-27574-59B1FDA3-19.0",
|
241
|
-
# "sg_event_id": "o70uHqbMSXOaaoveMZIjjg",
|
242
|
-
# "event": "spamreport"
|
243
|
-
# }
|
244
|
-
# ]
|
245
|
-
v['reason'] = 'feedback'
|
246
|
-
v['feedbacktype'] = 'abuse'
|
247
|
-
end
|
248
|
-
v['status'] ||= Sisimai::SMTP::Status.find(v['diagnosis']) || ''
|
249
|
-
v['replycode'] ||= Sisimai::SMTP::Reply.find(v['diagnosis']) || ''
|
250
|
-
|
251
|
-
# Generate pseudo message/rfc822 part
|
252
|
-
rfc822head = {
|
253
|
-
'from' => Sisimai::Address.undisclosed('s'),
|
254
|
-
'message-id' => v['sg_message_id'],
|
255
|
-
}
|
256
|
-
else
|
257
|
-
# {
|
258
|
-
# "status": "4.0.0",
|
259
|
-
# "created": "2011-09-16 22:02:19",
|
260
|
-
# "reason": "Unable to resolve MX host sendgrid.ne",
|
261
|
-
# "email": "esting@sendgrid.ne"
|
262
|
-
# },
|
263
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
264
|
-
v = dscontents[-1]
|
265
|
-
|
266
|
-
v['recipient'] = argvs['email']
|
267
|
-
v['date'] = argvs['created'] || ''
|
268
|
-
|
269
|
-
statuscode = argvs['status'] || ''
|
270
|
-
diagnostic = Sisimai::String.sweep(argvs['reason']) || ''
|
271
|
-
|
272
|
-
if statuscode =~ /\A[245]\d\d\z/
|
273
|
-
# "status": "550"
|
274
|
-
v['replycode'] = statuscode
|
275
|
-
|
276
|
-
elsif statuscode =~ /\A[245][.]\d[.]\d+\z/
|
277
|
-
# "status": "5.1.1"
|
278
|
-
v['status'] = statuscode
|
279
|
-
end
|
280
|
-
|
281
|
-
v['status'] ||= Sisimai::SMTP::Status.find(diagnostic) || ''
|
282
|
-
v['replycode'] ||= Sisimai::SMTP::Reply.find(diagnostic) || ''
|
283
|
-
v['diagnosis'] = argvs['reason'] || ''
|
284
|
-
v['agent'] = self.smtpagent
|
285
|
-
|
286
|
-
# Generate pseudo message/rfc822 part
|
287
|
-
rfc822head = {
|
288
|
-
'from' => Sisimai::Address.undisclosed('s'),
|
289
|
-
'date' => v['date'],
|
290
|
-
}
|
291
|
-
end
|
292
|
-
return { 'ds' => dscontents, 'rfc822' => rfc822head }
|
157
|
+
return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
|
293
158
|
end
|
294
159
|
|
295
160
|
end
|