sisimai 4.24.1-java → 4.25.0-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sisimai might be problematic. Click here for more details.

Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/ANALYTICAL-PRECISION +16 -25
  4. data/ChangeLog.md +41 -0
  5. data/Developers.mk +2 -2
  6. data/README-JA.md +13 -13
  7. data/README.md +13 -13
  8. data/lib/sisimai.rb +3 -7
  9. data/lib/sisimai/address.rb +25 -41
  10. data/lib/sisimai/arf.rb +58 -59
  11. data/lib/sisimai/bite.rb +0 -1
  12. data/lib/sisimai/bite/email.rb +7 -7
  13. data/lib/sisimai/bite/email/activehunter.rb +4 -3
  14. data/lib/sisimai/bite/email/amavis.rb +133 -0
  15. data/lib/sisimai/bite/email/amazonses.rb +53 -87
  16. data/lib/sisimai/bite/email/amazonworkmail.rb +51 -57
  17. data/lib/sisimai/bite/email/aol.rb +50 -76
  18. data/lib/sisimai/bite/email/apachejames.rb +2 -2
  19. data/lib/sisimai/bite/email/bigfoot.rb +47 -74
  20. data/lib/sisimai/bite/email/biglobe.rb +8 -9
  21. data/lib/sisimai/bite/email/courier.rb +56 -101
  22. data/lib/sisimai/bite/email/domino.rb +7 -8
  23. data/lib/sisimai/bite/email/einsundeins.rb +4 -5
  24. data/lib/sisimai/bite/email/exchange2003.rb +21 -22
  25. data/lib/sisimai/bite/email/exchange2007.rb +26 -28
  26. data/lib/sisimai/bite/email/exim.rb +48 -47
  27. data/lib/sisimai/bite/email/ezweb.rb +24 -36
  28. data/lib/sisimai/bite/email/facebook.rb +54 -79
  29. data/lib/sisimai/bite/email/fml.rb +10 -10
  30. data/lib/sisimai/bite/email/gmx.rb +6 -6
  31. data/lib/sisimai/bite/email/google.rb +12 -13
  32. data/lib/sisimai/bite/email/gsuite.rb +80 -108
  33. data/lib/sisimai/bite/email/imailserver.rb +16 -16
  34. data/lib/sisimai/bite/email/interscanmss.rb +4 -6
  35. data/lib/sisimai/bite/email/kddi.rb +9 -11
  36. data/lib/sisimai/bite/email/mailfoundry.rb +2 -2
  37. data/lib/sisimai/bite/email/mailmarshalsmtp.rb +2 -2
  38. data/lib/sisimai/bite/email/mailru.rb +12 -13
  39. data/lib/sisimai/bite/email/mcafee.rb +31 -25
  40. data/lib/sisimai/bite/email/messagelabs.rb +48 -87
  41. data/lib/sisimai/bite/email/messagingserver.rb +9 -10
  42. data/lib/sisimai/bite/email/mfilter.rb +16 -16
  43. data/lib/sisimai/bite/email/mxlogic.rb +11 -11
  44. data/lib/sisimai/bite/email/notes.rb +5 -6
  45. data/lib/sisimai/bite/email/office365.rb +25 -42
  46. data/lib/sisimai/bite/email/opensmtpd.rb +8 -8
  47. data/lib/sisimai/bite/email/outlook.rb +49 -67
  48. data/lib/sisimai/bite/email/postfix.rb +78 -112
  49. data/lib/sisimai/bite/email/qmail.rb +23 -23
  50. data/lib/sisimai/bite/email/receivingses.rb +53 -86
  51. data/lib/sisimai/bite/email/sendgrid.rb +65 -84
  52. data/lib/sisimai/bite/email/sendmail.rb +89 -117
  53. data/lib/sisimai/bite/email/surfcontrol.rb +15 -18
  54. data/lib/sisimai/bite/email/userdefined.rb +1 -1
  55. data/lib/sisimai/bite/email/v5sendmail.rb +3 -4
  56. data/lib/sisimai/bite/email/verizon.rb +7 -8
  57. data/lib/sisimai/bite/email/x1.rb +2 -2
  58. data/lib/sisimai/bite/email/x2.rb +2 -2
  59. data/lib/sisimai/bite/email/x3.rb +3 -3
  60. data/lib/sisimai/bite/email/x4.rb +22 -22
  61. data/lib/sisimai/bite/email/x5.rb +40 -49
  62. data/lib/sisimai/bite/email/yahoo.rb +3 -3
  63. data/lib/sisimai/bite/email/yandex.rb +54 -82
  64. data/lib/sisimai/bite/email/zoho.rb +6 -6
  65. data/lib/sisimai/bite/json/amazonses.rb +20 -20
  66. data/lib/sisimai/bite/json/sendgrid.rb +2 -2
  67. data/lib/sisimai/data.rb +27 -40
  68. data/lib/sisimai/datetime.rb +146 -162
  69. data/lib/sisimai/mda.rb +30 -31
  70. data/lib/sisimai/message/email.rb +83 -123
  71. data/lib/sisimai/message/json.rb +2 -4
  72. data/lib/sisimai/mime.rb +31 -34
  73. data/lib/sisimai/order/email.rb +23 -22
  74. data/lib/sisimai/reason.rb +61 -61
  75. data/lib/sisimai/reason/blocked.rb +139 -135
  76. data/lib/sisimai/reason/contenterror.rb +11 -10
  77. data/lib/sisimai/reason/exceedlimit.rb +4 -4
  78. data/lib/sisimai/reason/expired.rb +20 -20
  79. data/lib/sisimai/reason/filtered.rb +19 -18
  80. data/lib/sisimai/reason/hasmoved.rb +3 -3
  81. data/lib/sisimai/reason/hostunknown.rb +19 -19
  82. data/lib/sisimai/reason/mailboxfull.rb +49 -49
  83. data/lib/sisimai/reason/mailererror.rb +16 -16
  84. data/lib/sisimai/reason/mesgtoobig.rb +17 -17
  85. data/lib/sisimai/reason/networkerror.rb +19 -19
  86. data/lib/sisimai/reason/norelaying.rb +16 -16
  87. data/lib/sisimai/reason/notaccept.rb +9 -10
  88. data/lib/sisimai/reason/onhold.rb +1 -1
  89. data/lib/sisimai/reason/policyviolation.rb +21 -20
  90. data/lib/sisimai/reason/rejected.rb +53 -53
  91. data/lib/sisimai/reason/securityerror.rb +29 -29
  92. data/lib/sisimai/reason/spamdetected.rb +127 -127
  93. data/lib/sisimai/reason/suspend.rb +17 -17
  94. data/lib/sisimai/reason/systemerror.rb +22 -21
  95. data/lib/sisimai/reason/systemfull.rb +6 -6
  96. data/lib/sisimai/reason/toomanyconn.rb +19 -18
  97. data/lib/sisimai/reason/userunknown.rb +122 -121
  98. data/lib/sisimai/reason/vacation.rb +8 -8
  99. data/lib/sisimai/reason/virusdetected.rb +8 -8
  100. data/lib/sisimai/rfc1894.rb +142 -0
  101. data/lib/sisimai/rfc3464.rb +70 -70
  102. data/lib/sisimai/rfc3834.rb +15 -15
  103. data/lib/sisimai/rfc5322.rb +20 -36
  104. data/lib/sisimai/rhost.rb +1 -0
  105. data/lib/sisimai/rhost/exchangeonline.rb +31 -33
  106. data/lib/sisimai/rhost/franceptt.rb +23 -23
  107. data/lib/sisimai/rhost/godaddy.rb +28 -28
  108. data/lib/sisimai/rhost/googleapps.rb +39 -41
  109. data/lib/sisimai/rhost/kddi.rb +3 -3
  110. data/lib/sisimai/rhost/tencentqq.rb +51 -0
  111. data/lib/sisimai/smtp/error.rb +14 -21
  112. data/lib/sisimai/smtp/reply.rb +14 -13
  113. data/lib/sisimai/smtp/status.rb +178 -179
  114. data/lib/sisimai/string.rb +13 -12
  115. data/lib/sisimai/version.rb +1 -1
  116. data/set-of-emails/README.md +1 -5
  117. data/set-of-emails/maildir/bsd/arf-23.eml +49 -0
  118. data/set-of-emails/maildir/bsd/email-amavis-01.eml +78 -0
  119. data/set-of-emails/maildir/bsd/email-amavis-02.eml +78 -0
  120. data/set-of-emails/maildir/bsd/email-exchange2007-04.eml +146 -0
  121. data/set-of-emails/maildir/bsd/email-exim-60.eml +94 -0
  122. data/set-of-emails/maildir/bsd/email-ezweb-08.eml +49 -0
  123. data/set-of-emails/maildir/bsd/email-google-19.eml +67 -0
  124. data/set-of-emails/maildir/bsd/email-mcafee-05.eml +74 -0
  125. data/set-of-emails/maildir/bsd/email-messagingserver-12.eml +99 -0
  126. data/set-of-emails/maildir/bsd/email-postfix-46.eml +81 -0
  127. data/set-of-emails/maildir/bsd/email-postfix-47.eml +79 -0
  128. data/set-of-emails/maildir/bsd/email-postfix-48.eml +79 -0
  129. data/set-of-emails/maildir/bsd/email-postfix-49.eml +141 -0
  130. data/set-of-emails/maildir/bsd/email-postfix-50.eml +143 -0
  131. data/set-of-emails/maildir/bsd/email-postfix-51.eml +73 -0
  132. data/set-of-emails/maildir/bsd/email-postfix-52.eml +79 -0
  133. data/set-of-emails/maildir/bsd/email-postfix-53.eml +76 -0
  134. data/set-of-emails/maildir/bsd/email-postfix-54.eml +73 -0
  135. data/set-of-emails/maildir/bsd/email-postfix-55.eml +74 -0
  136. data/set-of-emails/maildir/bsd/email-postfix-56.eml +78 -0
  137. data/set-of-emails/maildir/bsd/email-qmail-10.eml +50 -0
  138. data/set-of-emails/maildir/bsd/email-x2-05.eml +38 -0
  139. data/set-of-emails/maildir/bsd/rhost-google-apps-02.eml +88 -0
  140. data/set-of-emails/maildir/bsd/rhost-tencentqq-01.eml +84 -0
  141. data/set-of-emails/maildir/bsd/rhost-tencentqq-02.eml +84 -0
  142. data/set-of-emails/maildir/bsd/rhost-tencentqq-03.eml +81 -0
  143. data/set-of-emails/maildir/dos/email-amavis-01.eml +78 -0
  144. data/set-of-emails/maildir/dos/email-apachejames-01.eml +1 -2
  145. data/set-of-emails/maildir/dos/email-messagelabs-01.eml +67 -50
  146. data/set-of-emails/maildir/dos/email-x4-01.eml +31 -76
  147. data/set-of-emails/maildir/dos/rhost-tencentqq-01.eml +84 -0
  148. data/set-of-emails/maildir/mac/email-amavis-01.eml +1 -4
  149. data/set-of-emails/maildir/mac/email-apachejames-01.eml +1 -9
  150. data/set-of-emails/maildir/mac/email-messagelabs-01.eml +1 -9
  151. data/set-of-emails/maildir/mac/email-x4-01.eml +1 -5
  152. data/set-of-emails/maildir/mac/rhost-tencentqq-01.eml +1 -4
  153. metadata +35 -4
  154. data/set-of-emails/logo/horizontalversions.png +0 -0
  155. data/set-of-emails/logo/icon.png +0 -0
@@ -67,7 +67,7 @@ module Sisimai::Bite::Email
67
67
  end
68
68
 
69
69
  if readcursor & Indicators[:'message-rfc822'] > 0
70
- # After "message/rfc822"
70
+ # Inside of the original message part
71
71
  if e.empty?
72
72
  blanklines += 1
73
73
  break if blanklines > 1
@@ -75,7 +75,7 @@ module Sisimai::Bite::Email
75
75
  end
76
76
  rfc822list << e
77
77
  else
78
- # Before "message/rfc822"
78
+ # Error message part
79
79
  next if (readcursor & Indicators[:deliverystatus]) == 0
80
80
  next if e.empty?
81
81
 
@@ -32,6 +32,10 @@ module Sisimai::Bite::Email
32
32
  match += 1 if mhead['received'].any? { |a| a.include?('.bigfoot.com') }
33
33
  return nil unless match > 0
34
34
 
35
+ require 'sisimai/rfc1894'
36
+ fieldtable = Sisimai::RFC1894.FIELDTABLE
37
+ permessage = {} # (Hash) Store values of each Per-Message field
38
+
35
39
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
36
40
  hasdivided = mbody.split("\n")
37
41
  havepassed = ['']
@@ -41,11 +45,6 @@ module Sisimai::Bite::Email
41
45
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
42
46
  commandtxt = '' # (String) SMTP Command name begin with the string '>>>'
43
47
  esmtpreply = '' # (String) Reply from remote server on SMTP session
44
- connvalues = 0 # (Integer) Flag, 1 if all the value of connheader have been set
45
- connheader = {
46
- 'date' => '', # The value of Arrival-Date header
47
- 'lhost' => '', # The value of Reporting-MTA header
48
- }
49
48
  v = nil
50
49
 
51
50
  while e = hasdivided.shift do
@@ -54,7 +53,7 @@ module Sisimai::Bite::Email
54
53
  p = havepassed[-2]
55
54
 
56
55
  if readcursor == 0
57
- # Beginning of the bounce message or delivery status part
56
+ # Beginning of the bounce message or message/delivery-status part
58
57
  if e =~ MarkingsOf[:message]
59
58
  readcursor |= Indicators[:deliverystatus]
60
59
  next
@@ -62,7 +61,7 @@ module Sisimai::Bite::Email
62
61
  end
63
62
 
64
63
  if (readcursor & Indicators[:'message-rfc822']) == 0
65
- # Beginning of the original message part
64
+ # Beginning of the original message part(message/rfc822)
66
65
  if e.start_with?(StartingOf[:rfc822][0])
67
66
  readcursor |= Indicators[:'message-rfc822']
68
67
  next
@@ -70,7 +69,7 @@ module Sisimai::Bite::Email
70
69
  end
71
70
 
72
71
  if readcursor & Indicators[:'message-rfc822'] > 0
73
- # After "message/rfc822"
72
+ # message/rfc822 OR text/rfc822-headers part
74
73
  if e.empty?
75
74
  blanklines += 1
76
75
  break if blanklines > 1
@@ -78,98 +77,72 @@ module Sisimai::Bite::Email
78
77
  end
79
78
  rfc822list << e
80
79
  else
81
- # Before "message/rfc822"
80
+ # message/delivery-status part
82
81
  next if (readcursor & Indicators[:deliverystatus]) == 0
83
82
  next if e.empty?
84
83
 
85
- if connvalues == connheader.keys.size
86
- # Final-Recipient: RFC822; <destinaion@example.net>
87
- # Action: failed
88
- # Status: 5.7.1
89
- # Remote-MTA: DNS; p01c11m075.mx.example.net
90
- # Diagnostic-Code: SMTP; 553 Invalid recipient destinaion@example.net (Mode: normal)
91
- # Last-Attempt-Date: Sun, 28 Dec 2014 18:17:16 -0800
84
+ if f = Sisimai::RFC1894.match(e)
85
+ # "e" matched with any field defined in RFC3464
86
+ next unless o = Sisimai::RFC1894.field(e)
92
87
  v = dscontents[-1]
93
88
 
94
- if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
95
- # Final-Recipient: RFC822; <destinaion@example.net>
96
- if v['recipient']
97
- # There are multiple recipient addresses in the message body.
98
- dscontents << Sisimai::Bite.DELIVERYSTATUS
99
- v = dscontents[-1]
89
+ if o[-1] == 'addr'
90
+ # Final-Recipient: rfc822; kijitora@example.jp
91
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
92
+ if o[0] == 'final-recipient'
93
+ # Final-Recipient: rfc822; kijitora@example.jp
94
+ if v['recipient']
95
+ # There are multiple recipient addresses in the message body.
96
+ dscontents << Sisimai::Bite.DELIVERYSTATUS
97
+ v = dscontents[-1]
98
+ end
99
+ v['recipient'] = o[2]
100
+ recipients += 1
101
+ else
102
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
103
+ v['alias'] = o[2]
100
104
  end
101
- v['recipient'] = Sisimai::Address.s3s4(cv[1])
102
- recipients += 1
103
-
104
- elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
105
- # Action: failed
106
- v['action'] = cv[1].downcase
107
-
108
- elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
109
- # Status: 5.7.1
110
- v['status'] = cv[1]
111
-
112
- elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
113
- # Remote-MTA: DNS; p01c11m075.mx.example.net
114
- v['rhost'] = cv[1].downcase
105
+ elsif o[-1] == 'code'
106
+ # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
107
+ v['spec'] = o[1]
108
+ v['diagnosis'] = o[2]
115
109
  else
116
- # Get error message
117
- if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
118
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
119
- v['spec'] = cv[1].upcase
120
- v['diagnosis'] = cv[2]
121
-
122
- elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
123
- # Continued line of the value of Diagnostic-Code header
124
- v['diagnosis'] << ' ' << cv[1]
125
- havepassed[-1] = 'Diagnostic-Code: ' << e
126
- end
110
+ # Other DSN fields defined in RFC3464
111
+ next unless fieldtable.key?(o[0])
112
+ v[fieldtable[o[0]]] = o[2]
113
+
114
+ next unless f == 1
115
+ permessage[fieldtable[o[0]]] = o[2]
127
116
  end
128
117
  else
129
- # ----- Transcript of session follows -----
130
- # >>> RCPT TO:<destinaion@example.net>
131
- # <<< 553 Invalid recipient destinaion@example.net (Mode: normal)
132
- #
133
- # --201412281816847
134
- # Content-Type: message/delivery-status
135
- #
136
- # Reporting-MTA: dns; litemail57.bigfoot.com
137
- # Arrival-Date: Sun, 28 Dec 2014 18:17:16 -0800
138
- #
139
- if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
140
- # Reporting-MTA: dns; mx.example.jp
141
- next unless connheader['lhost'].empty?
142
- connheader['lhost'] = cv[1].downcase
143
- connvalues += 1
144
-
145
- elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
146
- # Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
147
- next unless connheader['date'].empty?
148
- connheader['date'] = cv[1]
149
- connvalues += 1
150
- else
118
+ # The line does not begin with a DSN field defined in RFC3464
119
+ unless e.start_with?(' ')
151
120
  # ----- Transcript of session follows -----
152
121
  # >>> RCPT TO:<destinaion@example.net>
153
122
  # <<< 553 Invalid recipient destinaion@example.net (Mode: normal)
154
123
  if cv = e.match(/\A[>]{3}[ ]+([A-Z]{4})[ ]?/)
155
124
  # >>> DATA
156
125
  commandtxt = cv[1]
157
-
158
126
  elsif cv = e.match(/\A[<]{3}[ ]+(.+)\z/)
159
127
  # <<< Response
160
128
  esmtpreply = cv[1]
161
129
  end
162
-
130
+ else
131
+ # Continued line of the value of Diagnostic-Code field
132
+ next unless p.start_with?('Diagnostic-Code:')
133
+ next unless cv = e.match(/\A[ \t]+(.+)\z/)
134
+ v['diagnosis'] << ' ' << cv[1]
135
+ havepassed[-1] = 'Diagnostic-Code: ' << e
163
136
  end
164
-
165
137
  end
166
- end
138
+ end # End of message/delivery-status
167
139
  end
168
140
  return nil unless recipients > 0
169
141
 
170
142
  dscontents.each do |e|
171
143
  # Set default values if each value is empty.
172
- connheader.each_key { |a| e[a] ||= connheader[a] || '' }
144
+ e['lhost'] ||= permessage['rhost']
145
+ permessage.each_key { |a| e[a] ||= permessage[a] || '' }
173
146
 
174
147
  e['agent'] = self.smtpagent
175
148
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -13,8 +13,8 @@ module Sisimai::Bite::Email
13
13
  rfc822: ['Content-Type: message/rfc822'],
14
14
  }.freeze
15
15
  MessagesOf = {
16
- filtered: ['Mail Delivery Failed... User unknown'],
17
- mailboxfull: ["The number of messages in recipient's mailbox exceeded the local limit."],
16
+ 'filtered' => ['Mail Delivery Failed... User unknown'],
17
+ 'mailboxfull' => ["The number of messages in recipient's mailbox exceeded the local limit."],
18
18
  }.freeze
19
19
 
20
20
  def description; return 'BIGLOBE: http://www.biglobe.ne.jp'; end
@@ -62,7 +62,7 @@ module Sisimai::Bite::Email
62
62
  end
63
63
 
64
64
  if readcursor & Indicators[:'message-rfc822'] > 0
65
- # After "message/rfc822"
65
+ # Inside of the original message part
66
66
  if e.empty?
67
67
  blanklines += 1
68
68
  break if blanklines > 1
@@ -70,7 +70,7 @@ module Sisimai::Bite::Email
70
70
  end
71
71
  rfc822list << e
72
72
  else
73
- # Before "message/rfc822"
73
+ # Error message part
74
74
  next if (readcursor & Indicators[:deliverystatus]) == 0
75
75
  next if e.empty?
76
76
 
@@ -100,10 +100,9 @@ module Sisimai::Bite::Email
100
100
  end
101
101
 
102
102
  r = Sisimai::Address.s3s4(cv[1])
103
- if Sisimai::RFC5322.is_emailaddress(r)
104
- v['recipient'] = r
105
- recipients += 1
106
- end
103
+ next unless Sisimai::RFC5322.is_emailaddress(r)
104
+ v['recipient'] = r
105
+ recipients += 1
107
106
  else
108
107
  next if e =~ /\A[^\w]/
109
108
  v['diagnosis'] ||= ''
@@ -120,7 +119,7 @@ module Sisimai::Bite::Email
120
119
  MessagesOf.each_key do |r|
121
120
  # Verify each regular expression of session errors
122
121
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
123
- e['reason'] = r.to_s
122
+ e['reason'] = r
124
123
  break
125
124
  end
126
125
  end
@@ -16,12 +16,12 @@ module Sisimai::Bite::Email
16
16
 
17
17
  MessagesOf = {
18
18
  # courier/module.esmtp/esmtpclient.c:526| hard_error(del, ctf, "No such domain.");
19
- hostunknown: ['No such domain.'],
19
+ 'hostunknown' => ['No such domain.'],
20
20
  # courier/module.esmtp/esmtpclient.c:531| hard_error(del, ctf,
21
21
  # courier/module.esmtp/esmtpclient.c:532| "This domain's DNS violates RFC 1035.");
22
- systemerror: ["This domain's DNS violates RFC 1035."],
22
+ 'systemerror' => ["This domain's DNS violates RFC 1035."],
23
23
  # courier/module.esmtp/esmtpclient.c:535| soft_error(del, ctf, "DNS lookup failed.");
24
- networkerror: ['DNS lookup failed.'],
24
+ 'networkerror' => ['DNS lookup failed.'],
25
25
  }.freeze
26
26
 
27
27
  def description; return 'Courier MTA'; end
@@ -49,6 +49,10 @@ module Sisimai::Bite::Email
49
49
  end
50
50
  return nil unless match > 0
51
51
 
52
+ require 'sisimai/rfc1894'
53
+ fieldtable = Sisimai::RFC1894.FIELDTABLE
54
+ permessage = {} # (Hash) Store values of each Per-Message field
55
+
52
56
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
53
57
  hasdivided = mbody.split("\n")
54
58
  havepassed = ['']
@@ -57,12 +61,6 @@ module Sisimai::Bite::Email
57
61
  readcursor = 0 # (Integer) Points the current cursor position
58
62
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
59
63
  commandtxt = '' # (String) SMTP Command name begin with the string '>>>'
60
- connvalues = 0 # (Integer) Flag, 1 if all the value of connheader have been set
61
- connheader = {
62
- 'date' => '', # The value of Arrival-Date header
63
- 'rhost' => '', # The value of Reporting-MTA header
64
- 'lhost' => '', # The value of Received-From-MTA header
65
- }
66
64
  v = nil
67
65
 
68
66
  while e = hasdivided.shift do
@@ -71,7 +69,7 @@ module Sisimai::Bite::Email
71
69
  p = havepassed[-2]
72
70
 
73
71
  if readcursor == 0
74
- # Beginning of the bounce message or delivery status part
72
+ # Beginning of the bounce message or message/delivery-status part
75
73
  if e.include?(StartingOf[:message][0]) || e.include?(StartingOf[:message][1])
76
74
  readcursor |= Indicators[:deliverystatus]
77
75
  next
@@ -79,7 +77,7 @@ module Sisimai::Bite::Email
79
77
  end
80
78
 
81
79
  if (readcursor & Indicators[:'message-rfc822']) == 0
82
- # Beginning of the original message part
80
+ # Beginning of the original message part(message/rfc822)
83
81
  if e.start_with?(StartingOf[:rfc822][0], StartingOf[:rfc822][1])
84
82
  readcursor |= Indicators[:'message-rfc822']
85
83
  next
@@ -87,7 +85,7 @@ module Sisimai::Bite::Email
87
85
  end
88
86
 
89
87
  if readcursor & Indicators[:'message-rfc822'] > 0
90
- # After "message/rfc822"
88
+ # message/rfc822 OR text/rfc822-headers part
91
89
  if e.empty?
92
90
  blanklines += 1
93
91
  break if blanklines > 1
@@ -95,119 +93,76 @@ module Sisimai::Bite::Email
95
93
  end
96
94
  rfc822list << e
97
95
  else
98
- # Before "message/rfc822"
96
+ # message/delivery-status part
99
97
  next if (readcursor & Indicators[:deliverystatus]) == 0
100
98
  next if e.empty?
101
99
 
102
- if connvalues == connheader.keys.size
103
- # Final-Recipient: rfc822; kijitora@example.co.jp
104
- # Action: failed
105
- # Status: 5.0.0
106
- # Remote-MTA: dns; mx.example.co.jp [192.0.2.95]
107
- # Diagnostic-Code: smtp; 550 5.1.1 <kijitora@example.co.jp>... User Unknown
100
+ if f = Sisimai::RFC1894.match(e)
101
+ # "e" matched with any field defined in RFC3464
102
+ next unless o = Sisimai::RFC1894.field(e)
108
103
  v = dscontents[-1]
109
104
 
110
- if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
111
- # Final-Recipient: rfc822; kijitora@example.co.jp
112
- if v['recipient']
113
- # There are multiple recipient addresses in the message body.
114
- dscontents << Sisimai::Bite.DELIVERYSTATUS
115
- v = dscontents[-1]
105
+ if o[-1] == 'addr'
106
+ # Final-Recipient: rfc822; kijitora@example.jp
107
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
108
+ if o[0] == 'final-recipient'
109
+ # Final-Recipient: rfc822; kijitora@example.jp
110
+ if v['recipient']
111
+ # There are multiple recipient addresses in the message body.
112
+ dscontents << Sisimai::Bite.DELIVERYSTATUS
113
+ v = dscontents[-1]
114
+ end
115
+ v['recipient'] = o[2]
116
+ recipients += 1
117
+ else
118
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
119
+ v['alias'] = o[2]
116
120
  end
117
- v['recipient'] = cv[1]
118
- recipients += 1
119
-
120
- elsif cv = e.match(/\AX-Actual-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
121
- # X-Actual-Recipient: RFC822; kijitora@example.co.jp
122
- v['alias'] = cv[1]
123
-
124
- elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
125
- # Action: failed
126
- v['action'] = cv[1].downcase
127
-
128
- elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
129
- # Status: 5.1.1
130
- # Status:5.2.0
131
- # Status: 5.1.0 (permanent failure)
132
- v['status'] = cv[1]
133
-
134
- elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
135
- # Remote-MTA: DNS; mx.example.jp
136
- # Get the first element
137
- v['rhost'] = cv[1].downcase
138
- v['rhost'] = v['rhost'].split(' ').shift if v['rhost'].include?(' ')
139
-
140
- elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
141
- # Last-Attempt-Date: Fri, 14 Feb 2014 12:30:08 -0500
142
- v['date'] = cv[1]
121
+ elsif o[-1] == 'code'
122
+ # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
123
+ v['spec'] = o[1]
124
+ v['diagnosis'] = o[2]
143
125
  else
144
- if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
145
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
146
- v['spec'] = cv[1].upcase
147
- v['diagnosis'] = cv[2]
148
-
149
- elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
150
- # Continued line of the value of Diagnostic-Code header
151
- v['diagnosis'] << ' ' << cv[1]
152
- havepassed[-1] = 'Diagnostic-Code: ' << e
153
- end
126
+ # Other DSN fields defined in RFC3464
127
+ next unless fieldtable.key?(o[0])
128
+ v[fieldtable[o[0]]] = o[2]
129
+
130
+ next unless f == 1
131
+ permessage[fieldtable[o[0]]] = o[2]
154
132
  end
155
133
  else
156
- # This is a delivery status notification from marutamachi.example.org,
157
- # running the Courier mail server, version 0.65.2.
158
- #
159
- # The original message was received on Sat, 11 Dec 2010 12:19:57 +0900
160
- # from [127.0.0.1] (c10920.example.com [192.0.2.20])
161
- #
162
- # ---------------------------------------------------------------------------
163
- #
164
- # UNDELIVERABLE MAIL
165
- #
166
- # Your message to the following recipients cannot be delivered:
167
- #
168
- # <kijitora@example.co.jp>:
169
- # mx.example.co.jp [74.207.247.95]:
170
- # >>> RCPT TO:<kijitora@example.co.jp>
171
- # <<< 550 5.1.1 <kijitora@example.co.jp>... User Unknown
172
- #
173
- # ---------------------------------------------------------------------------
134
+ # The line does not begin with a DSN field defined in RFC3464
174
135
  if cv = e.match(/\A[>]{3}[ ]+([A-Z]{4})[ ]?/)
175
- # >>> DATA
136
+ # Your message to the following recipients cannot be delivered:
137
+ #
138
+ # <kijitora@example.co.jp>:
139
+ # mx.example.co.jp [74.207.247.95]:
140
+ # >>> RCPT TO:<kijitora@example.co.jp>
141
+ # <<< 550 5.1.1 <kijitora@example.co.jp>... User Unknown
142
+ #
176
143
  next unless commandtxt.empty?
177
144
  commandtxt = cv[1]
178
-
179
- elsif cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
180
- # Reporting-MTA: dns; mx.example.jp
181
- next unless connheader['rhost'].empty?
182
- connheader['rhost'] = cv[1].downcase
183
- connvalues += 1
184
-
185
- elsif cv = e.match(/\AReceived-From-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
186
- # Received-From-MTA: DNS; x1x2x3x4.dhcp.example.ne.jp
187
- next unless connheader['lhost'].empty?
188
- connheader['lhost'] = cv[1].downcase
189
- connvalues += 1
190
-
191
- elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
192
- # Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
193
- next unless connheader['date'].empty?
194
- connheader['date'] = cv[1]
195
- connvalues += 1
145
+ else
146
+ # Continued line of the value of Diagnostic-Code field
147
+ next unless p.start_with?('Diagnostic-Code:')
148
+ next unless cv = e.match(/\A[ \t]+(.+)\z/)
149
+ v['diagnosis'] << ' ' << cv[1]
150
+ havepassed[-1] = 'Diagnostic-Code: ' << e
196
151
  end
197
152
  end
198
- end
153
+ end # End of message/delivery-status
199
154
  end
200
155
  return nil unless recipients > 0
201
156
 
202
157
  dscontents.each do |e|
203
158
  # Set default values if each value is empty.
204
- connheader.each_key { |a| e[a] ||= connheader[a] || '' }
159
+ permessage.each_key { |a| e[a] ||= permessage[a] || '' }
205
160
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
206
161
 
207
162
  MessagesOf.each_key do |r|
208
163
  # Verify each regular expression of session errors
209
164
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
210
- e['reason'] = r.to_s
165
+ e['reason'] = r
211
166
  break
212
167
  end
213
168