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<^(?:[-]{50}|Content-Type:[ ]*message/rfc822)>.freeze
10
11
  MarkingsOf = {
11
12
  message: %r{\A(?:
12
13
  The[ ]user[(]s[)][ ]
@@ -15,7 +16,6 @@ module Sisimai::Lhost
15
16
  |[<][^ ]+[@][^ ]+[>]\z
16
17
  )
17
18
  }x,
18
- rfc822: %r#\A(?:[-]{50}|Content-Type:[ ]*message/rfc822)#,
19
19
  }.freeze
20
20
  ReFailures = {
21
21
  # notaccept: [ %r/The following recipients did not receive this message:/ ],
@@ -68,9 +68,8 @@ module Sisimai::Lhost
68
68
  require 'sisimai/rfc1894'
69
69
  fieldtable = Sisimai::RFC1894.FIELDTABLE
70
70
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
71
- hasdivided = mbody.split("\n")
72
- rfc822list = [] # (Array) Each line in message/rfc822 part string
73
- blanklines = 0 # (Integer) The number of blank lines
71
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
72
+ bodyslices = emailsteak[0].split("\n")
74
73
  readcursor = 0 # (Integer) Points the current cursor position
75
74
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
76
75
  rxboundary = %r/\A__SISIMAI_PSEUDO_BOUNDARY__\z/
@@ -85,83 +84,65 @@ module Sisimai::Lhost
85
84
  rxmessages = []
86
85
  ReFailures.each_value { |a| rxmessages << a }
87
86
 
88
- while e = hasdivided.shift do
87
+ while e = bodyslices.shift do
88
+ # Read error messages and delivery status lines from the head of the email
89
+ # to the previous line of the beginning of the original message.
89
90
  if readcursor == 0
90
91
  # Beginning of the bounce message or delivery status part
91
92
  readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
92
93
  end
93
-
94
- if (readcursor & Indicators[:'message-rfc822']) == 0
95
- # Beginning of the original message part
96
- if e =~ MarkingsOf[:rfc822] || e =~ rxboundary
97
- readcursor |= Indicators[:'message-rfc822']
98
- next
99
- end
100
- end
101
-
102
- if readcursor & Indicators[:'message-rfc822'] > 0
103
- # Inside of the original message part
104
- if e.empty?
105
- blanklines += 1
106
- break if blanklines > 1
107
- next
94
+ next if (readcursor & Indicators[:deliverystatus]) == 0
95
+ next if e.empty?
96
+
97
+ # The user(s) account is disabled.
98
+ #
99
+ # <***@ezweb.ne.jp>: 550 user unknown (in reply to RCPT TO command)
100
+ #
101
+ # -- OR --
102
+ # Each of the following recipients was rejected by a remote
103
+ # mail server.
104
+ #
105
+ # Recipient: <******@ezweb.ne.jp>
106
+ # >>> RCPT TO:<******@ezweb.ne.jp>
107
+ # <<< 550 <******@ezweb.ne.jp>: User unknown
108
+ v = dscontents[-1]
109
+
110
+ if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>]\z/) ||
111
+ e.match(/\A[<]([^ ]+[@][^ ]+)[>]:?(.*)\z/) ||
112
+ e.match(/\A[ \t]+Recipient: [<]([^ ]+[@][^ ]+)[>]/)
113
+
114
+ if v['recipient']
115
+ # There are multiple recipient addresses in the message body.
116
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
117
+ v = dscontents[-1]
108
118
  end
109
- rfc822list << e
110
- else
111
- # Error message part
112
- next if (readcursor & Indicators[:deliverystatus]) == 0
113
- next if e.empty?
114
-
115
- # The user(s) account is disabled.
116
- #
117
- # <***@ezweb.ne.jp>: 550 user unknown (in reply to RCPT TO command)
118
- #
119
- # -- OR --
120
- # Each of the following recipients was rejected by a remote
121
- # mail server.
122
- #
123
- # Recipient: <******@ezweb.ne.jp>
124
- # >>> RCPT TO:<******@ezweb.ne.jp>
125
- # <<< 550 <******@ezweb.ne.jp>: User unknown
126
- v = dscontents[-1]
127
-
128
- if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>]\z/) ||
129
- e.match(/\A[<]([^ ]+[@][^ ]+)[>]:?(.*)\z/) ||
130
- e.match(/\A[ \t]+Recipient: [<]([^ ]+[@][^ ]+)[>]/)
131
-
132
- if v['recipient']
133
- # There are multiple recipient addresses in the message body.
134
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
135
- v = dscontents[-1]
136
- end
137
119
 
138
- r = Sisimai::Address.s3s4(cv[1])
139
- v['recipient'] = r
140
- recipients += 1
120
+ r = Sisimai::Address.s3s4(cv[1])
121
+ v['recipient'] = r
122
+ recipients += 1
141
123
 
142
- elsif f = Sisimai::RFC1894.match(e)
143
- # "e" matched with any field defined in RFC3464
144
- next unless o = Sisimai::RFC1894.field(e)
145
- next unless fieldtable.key?(o[0])
146
- v[fieldtable[o[0]]] = o[2]
124
+ elsif f = Sisimai::RFC1894.match(e)
125
+ # "e" matched with any field defined in RFC3464
126
+ next unless o = Sisimai::RFC1894.field(e)
127
+ next unless fieldtable[o[0]]
128
+ v[fieldtable[o[0]]] = o[2]
147
129
 
130
+ else
131
+ # The line does not begin with a DSN field defined in RFC3464
132
+ next if Sisimai::String.is_8bit(e)
133
+ if cv = e.match(/\A[ \t]+[>]{3}[ \t]+([A-Z]{4})/)
134
+ # >>> RCPT TO:<******@ezweb.ne.jp>
135
+ v['command'] = cv[1]
148
136
  else
149
- # The line does not begin with a DSN field defined in RFC3464
150
- next if Sisimai::String.is_8bit(e)
151
- if cv = e.match(/\A[ \t]+[>]{3}[ \t]+([A-Z]{4})/)
152
- # >>> RCPT TO:<******@ezweb.ne.jp>
153
- v['command'] = cv[1]
137
+ # Check error message
138
+ if rxmessages.any? { |a| e =~ a }
139
+ # Check with regular expressions of each error
140
+ v['diagnosis'] ||= ''
141
+ v['diagnosis'] << ' ' << e
154
142
  else
155
- # Check error message
156
- if rxmessages.any? { |a| e =~ a }
157
- # Check with regular expressions of each error
158
- v['diagnosis'] ||= ''
159
- v['diagnosis'] << ' ' << e
160
- else
161
- # >>> 550
162
- v['alterrors'] ||= ''
163
- v['alterrors'] << ' ' << e
164
- end
143
+ # >>> 550
144
+ v['alterrors'] ||= ''
145
+ v['alterrors'] << ' ' << e
165
146
  end
166
147
  end
167
148
  end
@@ -212,8 +193,7 @@ module Sisimai::Lhost
212
193
  e['reason'] = 'userunknown'
213
194
  end
214
195
 
215
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
216
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
196
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
217
197
  end
218
198
 
219
199
  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 message was created automatically by Facebook.'],
12
- rfc822: ['Content-Disposition: inline'],
13
- }.freeze
10
+ ReBackbone = %r|^Content-Disposition:[ ]inline|.freeze
11
+ StartingOf = { message: ['This message was created automatically by Facebook.'] }.freeze
14
12
  ReFailures = {
15
13
  # http://postmaster.facebook.com/response_codes
16
14
  # NOT TESTD EXCEPT RCP-P2
@@ -95,90 +93,67 @@ module Sisimai::Lhost
95
93
  permessage = {} # (Hash) Store values of each Per-Message field
96
94
 
97
95
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
98
- hasdivided = mbody.split("\n")
99
- havepassed = ['']
100
- rfc822list = [] # (Array) Each line in message/rfc822 part string
101
- blanklines = 0 # (Integer) The number of blank lines
96
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
97
+ bodyslices = emailsteak[0].split("\n")
98
+ readslices = ['']
102
99
  readcursor = 0 # (Integer) Points the current cursor position
103
100
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
104
101
  fbresponse = '' # (String) Response code from Facebook
105
102
  v = nil
106
103
 
107
- while e = hasdivided.shift do
108
- # Save the current line for the next loop
109
- havepassed << e
110
- p = havepassed[-2]
104
+ while e = bodyslices.shift do
105
+ # Read error messages and delivery status lines from the head of the email
106
+ # to the previous line of the beginning of the original message.
107
+ readslices << e # Save the current line for the next loop
111
108
 
112
109
  if readcursor == 0
113
110
  # Beginning of the bounce message or message/delivery-status part
114
- if e == StartingOf[:message][0]
115
- readcursor |= Indicators[:deliverystatus]
116
- next
117
- end
118
- end
119
-
120
- if (readcursor & Indicators[:'message-rfc822']) == 0
121
- # Beginning of the original message part(message/rfc822)
122
- if e == StartingOf[:rfc822][0]
123
- readcursor |= Indicators[:'message-rfc822']
124
- next
125
- end
111
+ readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
112
+ next
126
113
  end
127
-
128
- if readcursor & Indicators[:'message-rfc822'] > 0
129
- # message/rfc822 OR text/rfc822-headers part
130
- if e.empty?
131
- blanklines += 1
132
- break if blanklines > 1
133
- next
134
- end
135
- rfc822list << e
136
- else
137
- # message/delivery-status part
138
- next if (readcursor & Indicators[:deliverystatus]) == 0
139
- next if e.empty?
140
-
141
- if f = Sisimai::RFC1894.match(e)
142
- # "e" matched with any field defined in RFC3464
143
- o = Sisimai::RFC1894.field(e) || next
144
- v = dscontents[-1]
145
-
146
- if o[-1] == 'addr'
114
+ next if (readcursor & Indicators[:deliverystatus]) == 0
115
+ next if e.empty?
116
+
117
+ if f = Sisimai::RFC1894.match(e)
118
+ # "e" matched with any field defined in RFC3464
119
+ o = Sisimai::RFC1894.field(e) || next
120
+ v = dscontents[-1]
121
+
122
+ if o[-1] == 'addr'
123
+ # Final-Recipient: rfc822; kijitora@example.jp
124
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
125
+ if o[0] == 'final-recipient'
147
126
  # Final-Recipient: rfc822; kijitora@example.jp
148
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
149
- if o[0] == 'final-recipient'
150
- # Final-Recipient: rfc822; kijitora@example.jp
151
- if v['recipient']
152
- # There are multiple recipient addresses in the message body.
153
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
154
- v = dscontents[-1]
155
- end
156
- v['recipient'] = o[2]
157
- recipients += 1
158
- else
159
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
160
- v['alias'] = o[2]
127
+ if v['recipient']
128
+ # There are multiple recipient addresses in the message body.
129
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
130
+ v = dscontents[-1]
161
131
  end
162
- elsif o[-1] == 'code'
163
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
164
- v['spec'] = o[1]
165
- v['diagnosis'] = o[2]
132
+ v['recipient'] = o[2]
133
+ recipients += 1
166
134
  else
167
- # Other DSN fields defined in RFC3464
168
- next unless fieldtable.key?(o[0])
169
- v[fieldtable[o[0]]] = o[2]
170
-
171
- next unless f == 1
172
- permessage[fieldtable[o[0]]] = o[2]
135
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
136
+ v['alias'] = o[2]
173
137
  end
138
+ elsif o[-1] == 'code'
139
+ # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
140
+ v['spec'] = o[1]
141
+ v['diagnosis'] = o[2]
174
142
  else
175
- # Continued line of the value of Diagnostic-Code field
176
- next unless p.start_with?('Diagnostic-Code:')
177
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
178
- v['diagnosis'] << ' ' << cv[1]
179
- havepassed[-1] = 'Diagnostic-Code: ' << e
143
+ # Other DSN fields defined in RFC3464
144
+ next unless fieldtable[o[0]]
145
+ v[fieldtable[o[0]]] = o[2]
146
+
147
+ next unless f == 1
148
+ permessage[fieldtable[o[0]]] = o[2]
180
149
  end
181
- end # End of message/delivery-status
150
+ else
151
+ # Continued line of the value of Diagnostic-Code field
152
+ next unless readslices[-2].start_with?('Diagnostic-Code:')
153
+ next unless cv = e.match(/\A[ \t]+(.+)\z/)
154
+ v['diagnosis'] << ' ' << cv[1]
155
+ readslices[-1] = 'Diagnostic-Code: ' << e
156
+ end
182
157
  end
183
158
  return nil unless recipients > 0
184
159
 
@@ -224,8 +199,7 @@ module Sisimai::Lhost
224
199
  e['reason'] = 'systemerror'
225
200
  end
226
201
 
227
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
228
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
202
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
229
203
  end
230
204
 
231
205
  end
@@ -7,7 +7,7 @@ module Sisimai::Lhost
7
7
  require 'sisimai/lhost'
8
8
 
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
- StartingOf = { rfc822: ['Original mail as follows:'] }.freeze
10
+ ReBackbone = %r|^Original[ ]mail[ ]as[ ]follows:|.freeze
11
11
  ErrorTitle = {
12
12
  'rejected' => %r{(?>
13
13
  (?:Ignored[ ])*NOT[ ]MEMBER[ ]article[ ]from[ ]
@@ -66,61 +66,37 @@ module Sisimai::Lhost
66
66
  return nil unless mhead['message-id'] =~ /\A[<]\d+[.]FML.+[@].+[>]\z/
67
67
 
68
68
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
69
- hasdivided = mbody.split("\n")
70
- rfc822list = [] # (Array) Each line in message/rfc822 part string
71
- blanklines = 0 # (Integer) The number of blank lines
69
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
70
+ bodyslices = emailsteak[0].split("\n")
72
71
  readcursor = 0 # (Integer) Points the current cursor position
73
72
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
74
73
  v = nil
75
74
 
76
- readcursor |= Indicators[:deliverystatus]
77
- while e = hasdivided.shift do
78
- if (readcursor & Indicators[:'message-rfc822']) == 0
79
- # Beginning of the original message part
80
- if e == StartingOf[:rfc822][0]
81
- readcursor |= Indicators[:'message-rfc822']
82
- next
83
- end
84
- end
75
+ while e = bodyslices.shift do
76
+ # Read error messages and delivery status lines from the head of the email
77
+ # to the previous line of the beginning of the original message.
78
+ next if (readcursor & Indicators[:deliverystatus]) == 0
79
+ next if e.empty?
85
80
 
86
- if readcursor & Indicators[:'message-rfc822'] > 0
87
- # After "Original mail as follows:" line
88
- #
89
- # From owner-2ndml@example.com Mon Nov 20 18:10:11 2017
90
- # Return-Path: <owner-2ndml@example.com>
91
- # ...
92
- #
93
- if e.empty?
94
- blanklines += 1
95
- break if blanklines > 1
96
- next
97
- end
98
- rfc822list << e.lstrip
99
- else
100
- # Error message part
101
- next if (readcursor & Indicators[:deliverystatus]) == 0
102
- next if e.empty?
81
+ # Duplicated Message-ID in <2ndml@example.com>.
82
+ # Original mail as follows:
83
+ v = dscontents[-1]
103
84
 
85
+ if cv = e.match(/[<]([^ ]+?[@][^ ]+?)[>][.]\z/)
104
86
  # Duplicated Message-ID in <2ndml@example.com>.
105
- # Original mail as follows:
106
- v = dscontents[-1]
107
-
108
- if cv = e.match(/[<]([^ ]+?[@][^ ]+?)[>][.]\z/)
109
- # Duplicated Message-ID in <2ndml@example.com>.
110
- if v['recipient']
111
- # There are multiple recipient addresses in the message body.
112
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
113
- v = dscontents[-1]
114
- end
115
- v['recipient'] = cv[1]
116
- v['diagnosis'] = e
117
- recipients += 1
118
- else
119
- # If you know the general guide of this list, please send mail with
120
- # the mail body
121
- v['diagnosis'] ||= ''
122
- v['diagnosis'] << e
87
+ if v['recipient']
88
+ # There are multiple recipient addresses in the message body.
89
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
90
+ v = dscontents[-1]
123
91
  end
92
+ v['recipient'] = cv[1]
93
+ v['diagnosis'] = e
94
+ recipients += 1
95
+ else
96
+ # If you know the general guide of this list, please send mail with
97
+ # the mail body
98
+ v['diagnosis'] ||= ''
99
+ v['diagnosis'] << e
124
100
  end
125
101
  end
126
102
  return nil unless recipients > 0
@@ -148,8 +124,7 @@ module Sisimai::Lhost
148
124
  end
149
125
  end
150
126
 
151
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
152
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
127
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
153
128
  end
154
129
 
155
130
  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 message was created automatically by mail delivery software'],
12
- rfc822: ['--- The header of the original message is following'],
13
- }.freeze
10
+ ReBackbone = %r|^---[ ]The[ ]header[ ]of[ ]the[ ]original[ ]message[ ]is[ ]following[.][ ]---|.freeze
11
+ StartingOf = { message: ['This message was created automatically by mail delivery software'] }.freeze
14
12
  MessagesOf = { 'expired' => ['delivery retry timeout exceeded'] }.freeze
15
13
 
16
14
  def description; return 'GMX: https://www.gmx.net'; end
@@ -39,91 +37,70 @@ module Sisimai::Lhost
39
37
  return nil unless mhead['x-gmx-antispam']
40
38
 
41
39
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
42
- hasdivided = mbody.split("\n")
43
- rfc822list = [] # (Array) Each line in message/rfc822 part string
44
- blanklines = 0 # (Integer) The number of blank lines
40
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
41
+ bodyslices = emailsteak[0].split("\n")
45
42
  readcursor = 0 # (Integer) Points the current cursor position
46
43
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
47
44
  v = nil
48
45
 
49
- while e = hasdivided.shift do
46
+ while e = bodyslices.shift do
47
+ # Read error messages and delivery status lines from the head of the email
48
+ # to the previous line of the beginning of the original message.
50
49
  if readcursor == 0
51
50
  # Beginning of the bounce message or delivery status part
52
- if e.start_with?(StartingOf[:message][0])
53
- readcursor |= Indicators[:deliverystatus]
54
- next
55
- end
56
- end
57
-
58
- if (readcursor & Indicators[:'message-rfc822']) == 0
59
- # Beginning of the original message part
60
- if e.start_with?(StartingOf[:rfc822][0])
61
- readcursor |= Indicators[:'message-rfc822']
62
- next
63
- end
51
+ readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
52
+ next
64
53
  end
65
-
66
- if readcursor & Indicators[:'message-rfc822'] > 0
67
- # Inside of the original message part
68
- if e.empty?
69
- blanklines += 1
70
- break if blanklines > 1
71
- next
54
+ next if (readcursor & Indicators[:deliverystatus]) == 0
55
+ next if e.empty?
56
+
57
+ # This message was created automatically by mail delivery software.
58
+ #
59
+ # A message that you sent could not be delivered to one or more of
60
+ # its recipients. This is a permanent error. The following address
61
+ # failed:
62
+ #
63
+ # "shironeko@example.jp":
64
+ # SMTP error from remote server after RCPT command:
65
+ # host: mx.example.jp
66
+ # 5.1.1 <shironeko@example.jp>... User Unknown
67
+ v = dscontents[-1]
68
+
69
+ if cv = e.match(/\A["]([^ ]+[@][^ ]+)["]:\z/) || e.match(/\A[<]([^ ]+[@][^ ]+)[>]\z/)
70
+ # "shironeko@example.jp":
71
+ # ---- OR ----
72
+ # <kijitora@6jo.example.co.jp>
73
+ #
74
+ # Reason:
75
+ # delivery retry timeout exceeded
76
+ if v['recipient']
77
+ # There are multiple recipient addresses in the message body.
78
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
79
+ v = dscontents[-1]
72
80
  end
73
- rfc822list << e
74
- else
75
- # Error message part
76
- next if (readcursor & Indicators[:deliverystatus]) == 0
77
- next if e.empty?
81
+ v['recipient'] = cv[1]
82
+ recipients += 1
78
83
 
79
- # This message was created automatically by mail delivery software.
80
- #
81
- # A message that you sent could not be delivered to one or more of
82
- # its recipients. This is a permanent error. The following address
83
- # failed:
84
- #
85
- # "shironeko@example.jp":
84
+ elsif cv = e.match(/\ASMTP error .+ ([A-Z]{4}) command:\z/)
86
85
  # SMTP error from remote server after RCPT command:
87
- # host: mx.example.jp
88
- # 5.1.1 <shironeko@example.jp>... User Unknown
89
- v = dscontents[-1]
90
-
91
- if cv = e.match(/\A["]([^ ]+[@][^ ]+)["]:\z/) || e.match(/\A[<]([^ ]+[@][^ ]+)[>]\z/)
92
- # "shironeko@example.jp":
93
- # ---- OR ----
94
- # <kijitora@6jo.example.co.jp>
95
- #
96
- # Reason:
97
- # delivery retry timeout exceeded
98
- if v['recipient']
99
- # There are multiple recipient addresses in the message body.
100
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
101
- v = dscontents[-1]
102
- end
103
- v['recipient'] = cv[1]
104
- recipients += 1
105
-
106
- elsif cv = e.match(/\ASMTP error .+ ([A-Z]{4}) command:\z/)
107
- # SMTP error from remote server after RCPT command:
108
- v['command'] = cv[1]
86
+ v['command'] = cv[1]
109
87
 
110
- elsif cv = e.match(/\Ahost:[ \t]*(.+)\z/)
111
- # host: mx.example.jp
112
- v['rhost'] = cv[1]
88
+ elsif cv = e.match(/\Ahost:[ \t]*(.+)\z/)
89
+ # host: mx.example.jp
90
+ v['rhost'] = cv[1]
91
+ else
92
+ # Get error message
93
+ if e =~ /\b[45][.]\d[.]\d\b/ || e =~ /[<][^ ]+[@][^ ]+[>]/ || e =~ /\b[45]\d{2}\b/
94
+ v['diagnosis'] ||= e
113
95
  else
114
- # Get error message
115
- if e =~ /\b[45][.]\d[.]\d\b/ || e =~ /[<][^ ]+[@][^ ]+[>]/ || e =~ /\b[45]\d{2}\b/
116
- v['diagnosis'] ||= e
117
- else
118
- next if e.empty?
119
- if e.start_with?('Reason:')
120
- # Reason:
121
- # delivery retry timeout exceeded
122
- v['diagnosis'] = e
123
-
124
- elsif v['diagnosis'] == 'Reason:'
125
- v['diagnosis'] = e
126
- end
96
+ next if e.empty?
97
+ if e.start_with?('Reason:')
98
+ # Reason:
99
+ # delivery retry timeout exceeded
100
+ v['diagnosis'] = e
101
+
102
+ elsif v['diagnosis'] == 'Reason:'
103
+ v['diagnosis'] = e
127
104
  end
128
105
  end
129
106
  end
@@ -142,8 +119,7 @@ module Sisimai::Lhost
142
119
  end
143
120
  end
144
121
 
145
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
146
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
122
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
147
123
  end
148
124
 
149
125
  end