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.

Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/ChangeLog.md +50 -0
  4. data/README-JA.md +10 -37
  5. data/README.md +10 -37
  6. data/lib/sisimai.rb +15 -64
  7. data/lib/sisimai/address.rb +13 -17
  8. data/lib/sisimai/arf.rb +4 -4
  9. data/lib/sisimai/data.rb +3 -5
  10. data/lib/sisimai/lhost.rb +0 -14
  11. data/lib/sisimai/lhost/activehunter.rb +31 -55
  12. data/lib/sisimai/lhost/amavis.rb +41 -66
  13. data/lib/sisimai/lhost/amazonses.rb +189 -235
  14. data/lib/sisimai/lhost/amazonworkmail.rb +48 -71
  15. data/lib/sisimai/lhost/aol.rb +49 -75
  16. data/lib/sisimai/lhost/apachejames.rb +60 -83
  17. data/lib/sisimai/lhost/bigfoot.rb +61 -85
  18. data/lib/sisimai/lhost/biglobe.rb +40 -62
  19. data/lib/sisimai/lhost/courier.rb +60 -82
  20. data/lib/sisimai/lhost/domino.rb +50 -76
  21. data/lib/sisimai/lhost/einsundeins.rb +57 -55
  22. data/lib/sisimai/lhost/exchange2003.rb +79 -101
  23. data/lib/sisimai/lhost/exchange2007.rb +66 -74
  24. data/lib/sisimai/lhost/exim.rb +119 -142
  25. data/lib/sisimai/lhost/ezweb.rb +53 -73
  26. data/lib/sisimai/lhost/facebook.rb +49 -75
  27. data/lib/sisimai/lhost/fml.rb +25 -50
  28. data/lib/sisimai/lhost/gmx.rb +55 -79
  29. data/lib/sisimai/lhost/google.rb +39 -66
  30. data/lib/sisimai/lhost/gsuite.rb +74 -94
  31. data/lib/sisimai/lhost/imailserver.rb +34 -67
  32. data/lib/sisimai/lhost/interscanmss.rb +33 -67
  33. data/lib/sisimai/lhost/kddi.rb +30 -52
  34. data/lib/sisimai/lhost/mailfoundry.rb +35 -57
  35. data/lib/sisimai/lhost/mailmarshalsmtp.rb +66 -89
  36. data/lib/sisimai/lhost/mailru.rb +51 -76
  37. data/lib/sisimai/lhost/mcafee.rb +53 -79
  38. data/lib/sisimai/lhost/messagelabs.rb +49 -75
  39. data/lib/sisimai/lhost/messagingserver.rb +91 -113
  40. data/lib/sisimai/lhost/mfilter.rb +50 -70
  41. data/lib/sisimai/lhost/mxlogic.rb +38 -63
  42. data/lib/sisimai/lhost/notes.rb +53 -82
  43. data/lib/sisimai/lhost/office365.rb +64 -81
  44. data/lib/sisimai/lhost/opensmtpd.rb +30 -52
  45. data/lib/sisimai/lhost/outlook.rb +49 -75
  46. data/lib/sisimai/lhost/postfix.rb +116 -117
  47. data/lib/sisimai/lhost/qmail.rb +33 -55
  48. data/lib/sisimai/lhost/receivingses.rb +49 -75
  49. data/lib/sisimai/lhost/sendgrid.rb +68 -203
  50. data/lib/sisimai/lhost/sendmail.rb +101 -125
  51. data/lib/sisimai/lhost/surfcontrol.rb +53 -79
  52. data/lib/sisimai/lhost/userdefined.rb +15 -35
  53. data/lib/sisimai/lhost/v5sendmail.rb +59 -89
  54. data/lib/sisimai/lhost/verizon.rb +75 -124
  55. data/lib/sisimai/lhost/x1.rb +30 -54
  56. data/lib/sisimai/lhost/x2.rb +28 -52
  57. data/lib/sisimai/lhost/x3.rb +44 -68
  58. data/lib/sisimai/lhost/x4.rb +34 -58
  59. data/lib/sisimai/lhost/x5.rb +42 -70
  60. data/lib/sisimai/lhost/yahoo.rb +44 -68
  61. data/lib/sisimai/lhost/yandex.rb +59 -85
  62. data/lib/sisimai/lhost/zoho.rb +54 -78
  63. data/lib/sisimai/mail.rb +5 -9
  64. data/lib/sisimai/mail/maildir.rb +10 -14
  65. data/lib/sisimai/mail/mbox.rb +8 -12
  66. data/lib/sisimai/mail/memory.rb +5 -9
  67. data/lib/sisimai/mail/stdin.rb +7 -11
  68. data/lib/sisimai/mda.rb +2 -2
  69. data/lib/sisimai/message.rb +51 -154
  70. data/lib/sisimai/mime.rb +2 -2
  71. data/lib/sisimai/order.rb +2 -27
  72. data/lib/sisimai/reason.rb +3 -5
  73. data/lib/sisimai/rfc1894.rb +1 -1
  74. data/lib/sisimai/rfc3464.rb +29 -29
  75. data/lib/sisimai/rfc3834.rb +7 -6
  76. data/lib/sisimai/rfc5322.rb +20 -31
  77. data/lib/sisimai/rhost/franceptt.rb +120 -24
  78. data/lib/sisimai/rhost/iua.rb +1 -1
  79. data/lib/sisimai/smtp/error.rb +7 -7
  80. data/lib/sisimai/version.rb +1 -1
  81. data/set-of-emails/maildir/bsd/email-einsundeins-03.eml +66 -0
  82. data/set-of-emails/maildir/bsd/email-exchange2007-05.eml +1469 -0
  83. data/set-of-emails/maildir/bsd/email-exchange2007-06.eml +764 -0
  84. data/set-of-emails/maildir/bsd/email-postfix-64.eml +96 -0
  85. data/set-of-emails/maildir/bsd/rfc3834-03.eml +26 -0
  86. data/set-of-emails/maildir/bsd/rhost-franceptt-04.eml +66 -0
  87. data/set-of-emails/maildir/bsd/rhost-franceptt-05.eml +96 -0
  88. data/set-of-emails/maildir/bsd/rhost-franceptt-06.eml +100 -0
  89. data/set-of-emails/maildir/bsd/rhost-franceptt-07.eml +97 -0
  90. data/set-of-emails/maildir/bsd/rhost-franceptt-08.eml +78 -0
  91. data/set-of-emails/maildir/bsd/rhost-franceptt-10.eml +79 -0
  92. data/set-of-emails/maildir/bsd/rhost-franceptt-11.eml +96 -0
  93. metadata +14 -9
  94. data/lib/sisimai/bite.rb +0 -42
  95. data/lib/sisimai/bite/email.rb +0 -18
  96. data/lib/sisimai/bite/json.rb +0 -16
  97. data/lib/sisimai/message/email.rb +0 -26
  98. data/lib/sisimai/message/json.rb +0 -24
  99. data/lib/sisimai/order/email.rb +0 -20
  100. data/lib/sisimai/order/json.rb +0 -16
@@ -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
- hasdivided = mbody.split("\n")
130
- rfc822list = [] # (Array) Each line in message/rfc822 part string
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 = hasdivided.shift do
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
- readcursor |= Indicators[:deliverystatus]
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
- if readcursor & Indicators[:'message-rfc822'] > 0
154
- # Inside of the original message part
155
- if e.empty?
156
- blanklines += 1
157
- break if blanklines > 1
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
- # 192.0.2.153 does not like recipient.
168
- # Remote host said: 550 5.1.1 <kijitora@example.jp>... User Unknown
169
- # Giving up on 192.0.2.153.
170
- v = dscontents[-1]
171
-
172
- if cv = e.match(/\A(?:To[ ]*:)?[<](.+[@].+)[>]:[ \t]*\z/)
173
- # <kijitora@example.jp>:
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
- elsif dscontents.size == recipients
183
- # Append error message
184
- next if e.empty?
185
- v['diagnosis'] ||= ''
186
- v['diagnosis'] << e + ' '
187
- v['alterrors'] = e if e.start_with?(StartingOf[:error][0])
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
- next if v['rhost']
190
- next unless cv = e.match(ReHost)
191
- v['rhost'] = cv[1]
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
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
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
- StartingOf = {
13
- message: ['This message could not be delivered.'],
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
- hasdivided = mbody.split("\n")
53
- havepassed = ['']
54
- rfc822list = [] # (Array) Each line in message/rfc822 part string
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 = hasdivided.shift do
61
- # Save the current line for the next loop
62
- havepassed << e
63
- p = havepassed[-2]
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
- readcursor |= Indicators[:deliverystatus]
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 readcursor & Indicators[:'message-rfc822'] > 0
82
- # message/rfc822 OR text/rfc822-headers part
83
- if e.empty?
84
- blanklines += 1
85
- break if blanklines > 1
86
- next
87
- end
88
- rfc822list << e
89
- else
90
- # message/delivery-status part
91
- next if (readcursor & Indicators[:deliverystatus]) == 0
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
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
102
- if o[0] == 'final-recipient'
103
- # Final-Recipient: rfc822; kijitora@example.jp
104
- if v['recipient']
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
- elsif o[-1] == 'code'
116
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
117
- v['spec'] = o[1]
118
- v['diagnosis'] = o[2]
85
+ v['recipient'] = o[2]
86
+ recipients += 1
119
87
  else
120
- # Other DSN fields defined in RFC3464
121
- next unless fieldtable.key?(o[0])
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
- # Continued line of the value of Diagnostic-Code field
129
- next unless p.start_with?('Diagnostic-Code:')
130
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
131
- v['diagnosis'] << ' ' << cv[1]
132
- havepassed[-1] = 'Diagnostic-Code: ' << e
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
- end # End of message/delivery-status
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
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
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
- StartingOf = {
11
- message: ['This is an automatically generated message from SendGrid.'],
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
- hasdivided = mbody.split("\n")
45
- havepassed = ['']
46
- rfc822list = [] # (Array) Each line in message/rfc822 part string
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 = hasdivided.shift do
54
- # Save the current line for the next loop
55
- havepassed << e
56
- p = havepassed[-2]
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
- readcursor |= Indicators[:deliverystatus]
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 readcursor & Indicators[:'message-rfc822'] > 0
75
- # message/rfc822 OR text/rfc822-headers part
76
- if e.empty?
77
- blanklines += 1
78
- break if blanklines > 1
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 f = Sisimai::RFC1894.match(e)
88
- # "e" matched with any field defined in RFC3464
89
- o = Sisimai::RFC1894.field(e)
90
- v = dscontents[-1]
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
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
104
- if o[0] == 'final-recipient'
105
- # Final-Recipient: rfc822; kijitora@example.jp
106
- if v['recipient']
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
- elsif o[-1] == 'code'
118
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
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
- # Other DSN fields defined in RFC3464
130
- next unless fieldtable.key?(o[0])
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
- # The line does not begin with a DSN field defined in RFC3464
138
- if cv = e.match(/.+ in (?:End of )?([A-Z]{4}).*\z/)
139
- # in RCPT TO, in MAIL FROM, end of DATA
140
- commandtxt = cv[1]
141
- else
142
- # Continued line of the value of Diagnostic-Code field
143
- next unless p.start_with?('Diagnostic-Code:')
144
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
145
- v['diagnosis'] << ' ' << cv[1]
146
- havepassed[-1] = 'Diagnostic-Code: ' << e
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 # End of message/delivery-status
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
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
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