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
@@ -8,10 +8,8 @@ module Sisimai::Lhost
8
8
  require 'sisimai/lhost'
9
9
 
10
10
  Indicators = Sisimai::Lhost.INDICATORS
11
- StartingOf = {
12
- message: ['This is an automatically generated Delivery Status Notification'],
13
- rfc822: ['Content-Type: message/rfc822'],
14
- }.freeze
11
+ ReBackbone = %r|^Content-Type: message/rfc822|.freeze
12
+ StartingOf = { message: ['This is an automatically generated Delivery Status Notification'] }.freeze
15
13
  MessagesOf = {
16
14
  'hostunknown' => ['The mail could not be delivered to the recipient because the domain is not reachable'],
17
15
  'userunknown' => ['Requested action not taken: mailbox unavailable'],
@@ -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.start_with?(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.start_with?(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
  end
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
@@ -8,7 +8,7 @@ module Sisimai::Lhost
8
8
 
9
9
  # Postfix manual - bounce(5) - http://www.postfix.org/bounce.5.html
10
10
  Indicators = Sisimai::Lhost.INDICATORS
11
- StartingOf = { rfc822: ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'] }.freeze
11
+ ReBackbone = %r<^Content-Type:[ ](?:message/rfc822|text/rfc822-headers)>.freeze
12
12
  MarkingsOf = {
13
13
  message: %r{\A(?>
14
14
  [ ]+The[ ](?:
@@ -28,6 +28,7 @@ module Sisimai::Lhost
28
28
  )
29
29
  )
30
30
  }x,
31
+ # :from => %r/ [(]Mail Delivery System[)]\z/,
31
32
  }.freeze
32
33
 
33
34
  def description; return 'Postfix'; end
@@ -46,155 +47,154 @@ module Sisimai::Lhost
46
47
  # part or nil if it failed to parse or
47
48
  # the arguments are missing
48
49
  def make(mhead, mbody)
49
- # :from => %r/ [(]Mail Delivery System[)]\z/,
50
50
  return nil unless mhead['subject'] == 'Undelivered Mail Returned to Sender'
51
51
 
52
52
  require 'sisimai/rfc1894'
53
+ require 'sisimai/address'
53
54
  fieldtable = Sisimai::RFC1894.FIELDTABLE
54
55
  permessage = {} # (Hash) Store values of each Per-Message field
55
56
 
56
57
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
57
- hasdivided = mbody.split("\n")
58
- havepassed = ['']
59
- rfc822list = [] # (Array) Each line in message/rfc822 part string
60
- blanklines = 0 # (Integer) The number of blank lines
58
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
59
+ bodyslices = emailsteak[0].split("\n")
60
+ readslices = ['']
61
61
  readcursor = 0 # (Integer) Points the current cursor position
62
62
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
63
+ nomessages = false # (Boolean) Delivery report unavailable
63
64
  commandset = [] # (Array) ``in reply to * command'' list
64
65
  anotherset = {} # Another error information
65
66
  v = nil
66
67
 
67
- while e = hasdivided.shift do
68
- # Save the current line for the next loop
69
- havepassed << e
70
- p = havepassed[-2]
68
+ while e = bodyslices.shift do
69
+ # Read error messages and delivery status lines from the head of the email
70
+ # to the previous line of the beginning of the original message.
71
+ readslices << e # Save the current line for the next loop
71
72
 
72
73
  if readcursor == 0
73
74
  # Beginning of the bounce message or message/delivery-status part
74
- if e =~ MarkingsOf[:message]
75
- readcursor |= Indicators[:deliverystatus]
76
- next
77
- end
75
+ readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
76
+ next
78
77
  end
78
+ next if (readcursor & Indicators[:deliverystatus]) == 0
79
+ next if e.empty?
79
80
 
80
- if (readcursor & Indicators[:'message-rfc822']) == 0
81
- # Beginning of the original message part(message/rfc822)
82
- if e.start_with?(StartingOf[:rfc822][0], StartingOf[:rfc822][1])
83
- readcursor |= Indicators[:'message-rfc822']
84
- next
85
- end
86
- end
81
+ if f = Sisimai::RFC1894.match(e)
82
+ # "e" matched with any field defined in RFC3464
83
+ next unless o = Sisimai::RFC1894.field(e)
84
+ v = dscontents[-1]
87
85
 
88
- if readcursor & Indicators[:'message-rfc822'] > 0
89
- # message/rfc822 OR text/rfc822-headers part
90
- if e.empty?
91
- blanklines += 1
92
- break if blanklines > 1
93
- next
94
- end
95
- rfc822list << e
96
- else
97
- # message/delivery-status part
98
- next if (readcursor & Indicators[:deliverystatus]) == 0
99
- next if e.empty?
100
-
101
- if f = Sisimai::RFC1894.match(e)
102
- # "e" matched with any field defined in RFC3464
103
- next unless o = Sisimai::RFC1894.field(e)
104
- v = dscontents[-1]
105
-
106
- if o[-1] == 'addr'
86
+ if o[-1] == 'addr'
87
+ # Final-Recipient: rfc822; kijitora@example.jp
88
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
89
+ if o[0] == 'final-recipient'
107
90
  # Final-Recipient: rfc822; kijitora@example.jp
108
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
109
- if o[0] == 'final-recipient'
110
- # Final-Recipient: rfc822; kijitora@example.jp
111
- if v['recipient']
112
- # There are multiple recipient addresses in the message body.
113
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
114
- v = dscontents[-1]
115
- end
116
- v['recipient'] = o[2]
117
- recipients += 1
118
- else
119
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
120
- v['alias'] = o[2]
91
+ if v['recipient']
92
+ # There are multiple recipient addresses in the message body.
93
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
94
+ v = dscontents[-1]
121
95
  end
122
- elsif o[-1] == 'code'
123
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
124
- v['spec'] = o[1]
125
- v['spec'] = 'SMTP' if v['spec'] == 'X-POSTFIX'
126
- v['diagnosis'] = o[2]
96
+ v['recipient'] = o[2]
97
+ recipients += 1
127
98
  else
128
- # Other DSN fields defined in RFC3464
129
- next unless fieldtable.key?(o[0])
130
- v[fieldtable[o[0]]] = o[2]
131
-
132
- next unless f == 1
133
- permessage[fieldtable[o[0]]] = o[2]
99
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
100
+ v['alias'] = o[2]
134
101
  end
102
+ elsif o[-1] == 'code'
103
+ # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
104
+ v['spec'] = o[1]
105
+ v['spec'] = 'SMTP' if v['spec'] == 'X-POSTFIX'
106
+ v['diagnosis'] = o[2]
107
+ else
108
+ # Other DSN fields defined in RFC3464
109
+ next unless fieldtable[o[0]]
110
+ v[fieldtable[o[0]]] = o[2]
111
+
112
+ next unless f == 1
113
+ permessage[fieldtable[o[0]]] = o[2]
114
+ end
115
+ else
116
+ # If you do so, please include this problem report. You can
117
+ # delete your own text from the attached returned message.
118
+ #
119
+ # The mail system
120
+ #
121
+ # <userunknown@example.co.jp>: host mx.example.co.jp[192.0.2.153] said: 550
122
+ # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
123
+ # command)
124
+ if readslices[-2].start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
125
+ # Continued line of the value of Diagnostic-Code header
126
+ v['diagnosis'] << ' ' << cv[1]
127
+ readslices[-1] = 'Diagnostic-Code: ' << e
128
+
129
+ elsif cv = e.match(/\A(X-Postfix-Sender):[ ]*rfc822;[ ]*(.+)\z/)
130
+ # X-Postfix-Sender: rfc822; shironeko@example.org
131
+ emailsteak[1] << cv[1] << ': ' << cv[2] << "\n"
132
+
135
133
  else
136
- # If you do so, please include this problem report. You can
137
- # delete your own text from the attached returned message.
138
- #
139
- # The mail system
140
- #
141
- # <userunknown@example.co.jp>: host mx.example.co.jp[192.0.2.153] said: 550
142
- # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
143
- # command)
144
- if p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
145
- # Continued line of the value of Diagnostic-Code header
146
- v['diagnosis'] << ' ' << cv[1]
147
- havepassed[-1] = 'Diagnostic-Code: ' << e
134
+ if cv = e.match(/[ \t][(]in reply to ([A-Z]{4}).*/)
135
+ # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
136
+ commandset << cv[1]
137
+ anotherset['diagnosis'] ||= ''
138
+ anotherset['diagnosis'] << ' ' << e
148
139
 
149
- elsif cv = e.match(/\A(X-Postfix-Sender):[ ]*rfc822;[ ]*(.+)\z/)
150
- # X-Postfix-Sender: rfc822; shironeko@example.org
151
- rfc822list << cv[1] << ': ' << cv[2]
140
+ elsif cv = e.match(/([A-Z]{4})[ \t]*.*command[)]\z/)
141
+ # to MAIL command)
142
+ commandset << cv[1]
143
+ anotherset['diagnosis'] ||= ''
144
+ anotherset['diagnosis'] << ' ' << e
152
145
 
153
146
  else
154
- if cv = e.match(/[ \t][(]in reply to ([A-Z]{4}).*/)
155
- # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
156
- commandset << cv[1]
157
- anotherset['diagnosis'] ||= ''
158
- anotherset['diagnosis'] << ' ' << e
147
+ # Alternative error message and recipient
148
+ if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>] [(]expanded from [<](.+)[>][)]:[ \t]*(.+)\z/)
149
+ # <r@example.ne.jp> (expanded from <kijitora@example.org>): user ...
150
+ anotherset['recipient'] = cv[1]
151
+ anotherset['alias'] = cv[2]
152
+ anotherset['diagnosis'] = cv[3]
159
153
 
160
- elsif cv = e.match(/([A-Z]{4})[ \t]*.*command[)]\z/)
161
- # to MAIL command)
162
- commandset << cv[1]
163
- anotherset['diagnosis'] ||= ''
164
- anotherset['diagnosis'] << ' ' << e
154
+ elsif cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>]:(.*)\z/)
155
+ # <kijitora@exmaple.jp>: ...
156
+ anotherset['recipient'] = cv[1]
157
+ anotherset['diagnosis'] = cv[2]
165
158
 
159
+ elsif e.include?('--- Delivery report unavailable ---')
160
+ # postfix-3.1.4/src/bounce/bounce_notify_util.c
161
+ # bounce_notify_util.c:602|if (bounce_info->log_handle == 0
162
+ # bounce_notify_util.c:602||| bounce_log_rewind(bounce_info->log_handle)) {
163
+ # bounce_notify_util.c:602|if (IS_FAILURE_TEMPLATE(bounce_info->template)) {
164
+ # bounce_notify_util.c:602| post_mail_fputs(bounce, "");
165
+ # bounce_notify_util.c:602| post_mail_fputs(bounce, "\t--- delivery report unavailable ---");
166
+ # bounce_notify_util.c:602| count = 1; /* xxx don't abort */
167
+ # bounce_notify_util.c:602|}
168
+ # bounce_notify_util.c:602|} else {
169
+ nomessages = true
166
170
  else
167
- # Alternative error message and recipient
168
- if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>] [(]expanded from [<](.+)[>][)]:[ \t]*(.+)\z/)
169
- # <r@example.ne.jp> (expanded from <kijitora@example.org>): user ...
170
- anotherset['recipient'] = cv[1]
171
- anotherset['alias'] = cv[2]
172
- anotherset['diagnosis'] = cv[3]
173
-
174
- elsif cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>]:(.*)\z/)
175
- # <kijitora@exmaple.jp>: ...
176
- anotherset['recipient'] = cv[1]
177
- anotherset['diagnosis'] = cv[2]
178
- else
179
- # Get error message continued from the previous line
180
- next unless anotherset['diagnosis']
181
- if e =~ /\A[ \t]{4}(.+)\z/
182
- # host mx.example.jp said:...
183
- anotherset['diagnosis'] << ' ' << e
184
- end
185
- end
171
+ # Get error message continued from the previous line
172
+ next unless anotherset['diagnosis']
173
+ if e =~ /\A[ \t]{4}(.+)\z/
174
+ # host mx.example.jp said:...
175
+ anotherset['diagnosis'] << ' ' << e
186
176
  end
177
+ end
187
178
  end
188
179
  end
189
- end # End of message/delivery-status
180
+ end
190
181
  end
191
182
 
192
183
  unless recipients > 0
193
- # Fallback: set recipient address from error message
194
- unless anotherset['recipient'].to_s.empty?
195
- # Set recipient address
184
+ # Fallback: get a recipient address from error messages
185
+ if anotherset['recipient'].to_s.size > 0
186
+ # Set a recipient address
196
187
  dscontents[-1]['recipient'] = anotherset['recipient']
197
188
  recipients += 1
189
+ else
190
+ # Get a recipient address from message/rfc822 part if the delivery
191
+ # report was unavailable: '--- Delivery report unavailable ---'
192
+ if nomessages && cv = emailsteak[1].match(/^To:[ ]*(.+)$/)
193
+ # Try to get a recipient address from To: field in the original
194
+ # message at message/rfc822 part
195
+ dscontents[-1]['recipient'] = Sisimai::Address.s3s4(cv[1])
196
+ recipients += 1
197
+ end
198
198
  end
199
199
  end
200
200
  return nil unless recipients > 0
@@ -204,9 +204,6 @@ module Sisimai::Lhost
204
204
  e['lhost'] ||= permessage['rhost']
205
205
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
206
206
 
207
- e['agent'] = self.smtpagent
208
- e['command'] = commandset.shift || ''
209
-
210
207
  if anotherset['diagnosis']
211
208
  # Copy alternative error message
212
209
  e['diagnosis'] = anotherset['diagnosis'] unless e['diagnosis']
@@ -247,12 +244,14 @@ module Sisimai::Lhost
247
244
  end
248
245
 
249
246
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
247
+ e['command'] = commandset.shift || nil
248
+ e['command'] ||= 'HELO' if e['diagnosis'] =~ /refused to talk to me:/
250
249
  e['spec'] ||= 'SMTP' if e['diagnosis'] =~ /host .+ said:/
250
+ e['agent'] = self.smtpagent
251
251
  e.each_key { |a| e[a] ||= '' }
252
252
  end
253
253
 
254
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
255
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
254
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
256
255
  end
257
256
 
258
257
  end