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
@@ -18,7 +18,7 @@ module Sisimai::Bite::Email
18
18
  # X-SEF-ZeroHour-RefID: fgs=000000000
19
19
  # X-SEF-Processed: 0_0_0_000__2010_04_29_23_34_45
20
20
  # X-Mailer: SurfControl E-mail Filter
21
- def headerlist; return ['X-SEF-Processed', 'X-Mailer']; end
21
+ def headerlist; return %w[x-sef-processed x-mailer]; end
22
22
 
23
23
  # Parse bounce messages from SurfControl
24
24
  # @param [Hash] mhead Message headers of a bounce email
@@ -37,6 +37,8 @@ module Sisimai::Bite::Email
37
37
  return nil unless mhead['x-mailer']
38
38
  return nil unless mhead['x-mailer'] == 'SurfControl E-mail Filter'
39
39
 
40
+ require 'sisimai/rfc1894'
41
+ fieldtable = Sisimai::RFC1894.FIELDTABLE
40
42
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
41
43
  hasdivided = mbody.split("\n")
42
44
  havepassed = ['']
@@ -68,7 +70,7 @@ module Sisimai::Bite::Email
68
70
  end
69
71
 
70
72
  if readcursor & Indicators[:'message-rfc822'] > 0
71
- # After "message/rfc822"
73
+ # Inside of the original message part
72
74
  if e.empty?
73
75
  blanklines += 1
74
76
  break if blanklines > 1
@@ -76,7 +78,7 @@ module Sisimai::Bite::Email
76
78
  end
77
79
  rfc822list << e
78
80
  else
79
- # Before "message/rfc822"
81
+ # Error message part
80
82
  next if (readcursor & Indicators[:deliverystatus]) == 0
81
83
  next if e.empty?
82
84
 
@@ -111,23 +113,18 @@ module Sisimai::Bite::Email
111
113
  v['diagnosis'] = cv[2]
112
114
  else
113
115
  # Fallback, parse RFC3464 headers.
114
- if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
115
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
116
- v['spec'] = cv[1].upcase
117
- v['diagnosis'] = cv[2]
118
-
119
- elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ ]+(.+)\z/)
120
- # Continued line of the value of Diagnostic-Code header
116
+ if f = Sisimai::RFC1894.match(e)
117
+ # "e" matched with any field defined in RFC3464
118
+ next unless o = Sisimai::RFC1894.field(e)
119
+ next if o[1] == 'final-recipient'
120
+ next unless fieldtable.key?(o[0])
121
+ v[fieldtable[o[0]]] = o[2]
122
+ else
123
+ # Continued line of the value of Diagnostic-Code field
124
+ next unless p.start_with?('Diagnostic-Code:')
125
+ next unless cv = e.match(/\A[ \t]+(.+)\z/)
121
126
  v['diagnosis'] << ' ' << cv[1]
122
127
  havepassed[-1] = 'Diagnostic-Code: ' << e
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.0.-
130
- v['status'] = cv[1]
131
128
  end
132
129
  end
133
130
  end
@@ -21,7 +21,7 @@ module Sisimai::Bite::Email
21
21
 
22
22
  def description; return 'Module description'; end
23
23
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
24
- def headerlist; return ['X-Some-UserDefined-Header']; end
24
+ def headerlist; return %w[x-some-userdefined-header]; end
25
25
 
26
26
  # @abstract Template for User-Defined MTA module
27
27
  # @param [Hash] mhead Message headers of a bounce email
@@ -83,7 +83,7 @@ module Sisimai::Bite::Email
83
83
  end
84
84
 
85
85
  if readcursor & Indicators[:'message-rfc822'] > 0
86
- # After "message/rfc822"
86
+ # Inside of the original message part
87
87
  if e.empty?
88
88
  blanklines += 1
89
89
  break if blanklines > 1
@@ -91,7 +91,7 @@ module Sisimai::Bite::Email
91
91
  end
92
92
  rfc822list << e
93
93
  else
94
- # Before "message/rfc822"
94
+ # Error message part
95
95
  next if (readcursor & Indicators[:deliverystatus]) == 0
96
96
  next if e.empty?
97
97
 
@@ -149,9 +149,8 @@ module Sisimai::Bite::Email
149
149
  if recipients == 0
150
150
  # Get the recipient address from the original message
151
151
  rfc822list.each do |e|
152
- next unless cv = e.match(/^To: (.+)$/m)
153
-
154
152
  # The value of To: header in the original message
153
+ next unless cv = e.match(/^To: (.+)$/m)
155
154
  dscontents[0]['recipient'] = Sisimai::Address.s3s4(cv[1])
156
155
  recipients = 1
157
156
  break
@@ -47,7 +47,6 @@ module Sisimai::Bite::Email
47
47
  markingsof = {} # (Hash) Delimiter patterns
48
48
  startingof = {} # (Hash) Delimiter strings
49
49
  messagesof = {} # (Hash) Error message patterns
50
- boundary00 = '' # (String) Boundary string
51
50
  v = nil
52
51
 
53
52
  if match == 1
@@ -58,7 +57,7 @@ module Sisimai::Bite::Email
58
57
  }
59
58
  messagesof = {
60
59
  # The attempted recipient address does not exist.
61
- userunknown: ['550 - Requested action not taken: no such user here'],
60
+ 'userunknown' => ['550 - Requested action not taken: no such user here'],
62
61
  }
63
62
  boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
64
63
  markingsof[:rfc822] = Regexp.new('\A' << Regexp.escape('--' << boundary00 << '--') << '\z') unless boundary00.empty?
@@ -81,7 +80,7 @@ module Sisimai::Bite::Email
81
80
  end
82
81
 
83
82
  if readcursor & Indicators[:'message-rfc822'] > 0
84
- # After "message/rfc822"
83
+ # Inside of the original message part
85
84
  if e.empty?
86
85
  blanklines += 1
87
86
  break if blanklines > 1
@@ -89,7 +88,7 @@ module Sisimai::Bite::Email
89
88
  end
90
89
  rfc822list << e
91
90
  else
92
- # Before "message/rfc822"
91
+ # Error message part
93
92
  next if (readcursor & Indicators[:deliverystatus]) == 0
94
93
  next if e.empty?
95
94
 
@@ -128,7 +127,7 @@ module Sisimai::Bite::Email
128
127
  # vzwpix.com
129
128
  startingof = { message: ['Message could not be delivered to mobile'] }
130
129
  markingsof = { rfc822: %r/\A__BOUNDARY_STRING_HERE__\z/ }
131
- messagesof = { userunknown: ['No valid recipients for this MM'] }
130
+ messagesof = { 'userunknown' => ['No valid recipients for this MM'] }
132
131
  boundary00 = Sisimai::MIME.boundary(mhead['content-type'])
133
132
  markingsof[:rfc822] = Regexp.new('\A' << Regexp.escape('--' << boundary00 << '--') << '\z') unless boundary00.empty?
134
133
 
@@ -150,7 +149,7 @@ module Sisimai::Bite::Email
150
149
  end
151
150
 
152
151
  if readcursor & Indicators[:'message-rfc822'] > 0
153
- # After "message/rfc822"
152
+ # Inside of the original message part
154
153
  if e.empty?
155
154
  blanklines += 1
156
155
  break if blanklines > 1
@@ -158,7 +157,7 @@ module Sisimai::Bite::Email
158
157
  end
159
158
  rfc822list << e
160
159
  else
161
- # Before "message/rfc822"
160
+ # Error message part
162
161
  next if (readcursor & Indicators[:deliverystatus]) == 0
163
162
  next if e.empty?
164
163
 
@@ -211,7 +210,7 @@ module Sisimai::Bite::Email
211
210
  messagesof.each_key do |r|
212
211
  # Verify each regular expression of session errors
213
212
  next unless messagesof[r].any? { |a| e['diagnosis'].include?(a) }
214
- e['reason'] = r.to_s
213
+ e['reason'] = r
215
214
  break
216
215
  end
217
216
  end
@@ -58,7 +58,7 @@ module Sisimai::Bite::Email
58
58
  end
59
59
 
60
60
  if readcursor & Indicators[:'message-rfc822'] > 0
61
- # After "message/rfc822"
61
+ # Inside of the original message part
62
62
  if e.empty?
63
63
  blanklines += 1
64
64
  break if blanklines > 1
@@ -66,7 +66,7 @@ module Sisimai::Bite::Email
66
66
  end
67
67
  rfc822list << e
68
68
  else
69
- # Before "message/rfc822"
69
+ # Error message part
70
70
  next if (readcursor & Indicators[:deliverystatus]) == 0
71
71
  next if e.empty?
72
72
 
@@ -57,7 +57,7 @@ module Sisimai::Bite::Email
57
57
  end
58
58
 
59
59
  if readcursor & Indicators[:'message-rfc822'] > 0
60
- # After "message/rfc822"
60
+ # Inside of the original message part
61
61
  if e.empty?
62
62
  blanklines += 1
63
63
  break if blanklines > 2
@@ -65,7 +65,7 @@ module Sisimai::Bite::Email
65
65
  end
66
66
  rfc822list << e
67
67
  else
68
- # Before "message/rfc822"
68
+ # Error message part
69
69
  next if (readcursor & Indicators[:deliverystatus]) == 0
70
70
  next if e.empty?
71
71
 
@@ -57,7 +57,7 @@ module Sisimai::Bite::Email
57
57
  end
58
58
 
59
59
  if readcursor & Indicators[:'message-rfc822'] > 0
60
- # After "message/rfc822"
60
+ # Inside of the original message part
61
61
  if e.empty?
62
62
  blanklines += 1
63
63
  break if blanklines > 1
@@ -65,7 +65,7 @@ module Sisimai::Bite::Email
65
65
  end
66
66
  rfc822list << e
67
67
  else
68
- # Before "message/rfc822"
68
+ # Error message part
69
69
  next if (readcursor & Indicators[:deliverystatus]) == 0
70
70
  next if e.empty?
71
71
 
@@ -114,7 +114,7 @@ module Sisimai::Bite::Email
114
114
  dscontents.each do |e|
115
115
  e['agent'] = self.smtpagent
116
116
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
117
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
117
+ e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
118
118
  e.each_key { |a| e[a] ||= '' }
119
119
  end
120
120
 
@@ -43,21 +43,21 @@ module Sisimai::Bite::Email
43
43
  ReSMTP = {
44
44
  # Error text regular expressions which defined in qmail-remote.c
45
45
  # qmail-remote.c:225| if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
46
- conn: %r/(?:Error:)?Connected to .+ but greeting failed[.]/,
46
+ 'conn' => %r/(?:Error:)?Connected to .+ but greeting failed[.]/,
47
47
  # qmail-remote.c:231| if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
48
- ehlo: %r/(?:Error:)?Connected to .+ but my name was rejected[.]/,
48
+ 'ehlo' => %r/(?:Error:)?Connected to .+ but my name was rejected[.]/,
49
49
  # qmail-remote.c:238| if (code >= 500) quit("DConnected to "," but sender was rejected");
50
50
  # reason = rejected
51
- mail: %r/(?:Error:)?Connected to .+ but sender was rejected[.]/,
51
+ 'mail' => %r/(?:Error:)?Connected to .+ but sender was rejected[.]/,
52
52
  # qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
53
53
  # qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
54
54
  # reason = userunknown
55
- rcpt: %r/(?:Error:)?.+ does not like recipient[.]/,
55
+ 'rcpt' => %r/(?:Error:)?.+ does not like recipient[.]/,
56
56
  # qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
57
57
  # qmail-remote.c:266| if (code >= 400) quit("Z"," failed on DATA command");
58
58
  # qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
59
59
  # qmail-remote.c:272| if (code >= 400) quit("Z"," failed after I sent the message");
60
- data: %r{(?:
60
+ 'data' => %r{(?:
61
61
  (?:Error:)?.+[ ]failed[ ]on[ ]DATA[ ]command[.]
62
62
  |(?:Error:)?.+[ ]failed[ ]after[ ]I[ ]sent[ ]the[ ]message[.]
63
63
  )
@@ -77,10 +77,10 @@ module Sisimai::Bite::Email
77
77
  ReCommands = %r/Sorry, no SMTP connection got far enough; most progress was ([A-Z]{4})[ ]/
78
78
  FailOnLDAP = {
79
79
  # qmail-ldap-1.03-20040101.patch:19817 - 19866
80
- suspend: ['Mailaddress is administrative?le?y disabled'], # 5.2.1
81
- userunknown: ['Sorry, no mailbox here by that name'], # 5.1.1
82
- exceedlimit: ['The message exeeded the maximum size the user accepts'], # 5.2.3
83
- systemerror: [
80
+ 'suspend' => ['Mailaddress is administrative?le?y disabled'], # 5.2.1
81
+ 'userunknown' => ['Sorry, no mailbox here by that name'], # 5.1.1
82
+ 'exceedlimit' => ['The message exeeded the maximum size the user accepts'], # 5.2.3
83
+ 'systemerror' => [
84
84
  'Automatic homedir creator crashed', # 4.3.0
85
85
  'Illegal value in LDAP attribute', # 5.3.5
86
86
  'LDAP attribute is not given but mandatory', # 5.3.5
@@ -97,22 +97,22 @@ module Sisimai::Bite::Email
97
97
  MessagesOf = {
98
98
  # qmail-local.c:589| strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)");
99
99
  # qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
100
- userunknown: ['no mailbox here by that name', 'does not like recipient.'],
100
+ 'userunknown' => ['no mailbox here by that name', 'does not like recipient.'],
101
101
  # error_str.c:192| X(EDQUOT,"disk quota exceeded")
102
- mailboxfull: ['disk quota exceeded'],
102
+ 'mailboxfull' => ['disk quota exceeded'],
103
103
  # qmail-qmtpd.c:233| ... result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
104
104
  # qmail-smtpd.c:391| ... out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return;
105
- mesgtoobig: ['Message size exceeds fixed maximum message size:'],
105
+ 'mesgtoobig' => ['Message size exceeds fixed maximum message size:'],
106
106
  # qmail-remote.c:68| Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie();
107
107
  # qmail-remote.c:78| Sorry, I couldn't find any host named ");
108
- hostunknown: ["Sorry, I couldn't find any host "],
109
- systemfull: ['Requested action not taken: mailbox unavailable (not enough free space)'],
110
- systemerror: [
108
+ 'hostunknown' => ["Sorry, I couldn't find any host "],
109
+ 'systemfull' => ['Requested action not taken: mailbox unavailable (not enough free space)'],
110
+ 'systemerror' => [
111
111
  'bad interpreter: No such file or directory',
112
112
  'system error',
113
113
  'Unable to',
114
114
  ],
115
- networkerror: [
115
+ 'networkerror' => [
116
116
  "Sorry, I wasn't able to establish an SMTP connection",
117
117
  "Sorry, I couldn't find a mail exchanger or IP address",
118
118
  "Sorry. Although I'm listed as a best-preference MX or A for that host",
@@ -171,7 +171,7 @@ module Sisimai::Bite::Email
171
171
  end
172
172
 
173
173
  if readcursor & Indicators[:'message-rfc822'] > 0
174
- # After "message/rfc822"
174
+ # Inside of the original message part
175
175
  if e.empty?
176
176
  blanklines += 1
177
177
  break if blanklines > 1
@@ -179,7 +179,7 @@ module Sisimai::Bite::Email
179
179
  end
180
180
  rfc822list << e
181
181
  else
182
- # Before "message/rfc822"
182
+ # Error message part
183
183
  next if (readcursor & Indicators[:deliverystatus]) == 0
184
184
  next if e.empty?
185
185
 
@@ -223,7 +223,7 @@ module Sisimai::Bite::Email
223
223
  ReSMTP.each_key do |r|
224
224
  # Verify each regular expression of SMTP commands
225
225
  next unless e['diagnosis'] =~ ReSMTP[r]
226
- e['command'] = r.to_s.upcase
226
+ e['command'] = r.upcase
227
227
  break
228
228
  end
229
229
 
@@ -254,12 +254,12 @@ module Sisimai::Bite::Email
254
254
  if e['alterrors']
255
255
  # Check the value of "alterrors"
256
256
  next unless MessagesOf[r].any? { |a| e['alterrors'].include?(a) }
257
- e['reason'] = r.to_s
257
+ e['reason'] = r
258
258
  end
259
259
  break if e['reason']
260
260
 
261
261
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
262
- e['reason'] = r.to_s
262
+ e['reason'] = r
263
263
  break
264
264
  end
265
265
 
@@ -267,7 +267,7 @@ module Sisimai::Bite::Email
267
267
  FailOnLDAP.each_key do |r|
268
268
  # Verify each regular expression of LDAP errors
269
269
  next unless FailOnLDAP[r].any? { |a| e['diagnosis'].include?(a) }
270
- e['reason'] = r.to_s
270
+ e['reason'] = r
271
271
  break
272
272
  end
273
273
  end
@@ -48,6 +48,8 @@ module Sisimai::Bite::Email
48
48
  end
49
49
  return nil if match < 2
50
50
 
51
+ require 'sisimai/rfc1894'
52
+ fieldtable = Sisimai::RFC1894.FIELDTABLE
51
53
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
52
54
  hasdivided = mbody.split("\n")
53
55
  havepassed = ['']
@@ -63,7 +65,7 @@ module Sisimai::Bite::Email
63
65
  p = havepassed[-2]
64
66
 
65
67
  if readcursor == 0
66
- # Beginning of the bounce message or delivery status part
68
+ # Beginning of the bounce message or message/delivery-status part
67
69
  if e.start_with?(StartingOf[:message][0])
68
70
  readcursor |= Indicators[:deliverystatus]
69
71
  next
@@ -71,7 +73,7 @@ module Sisimai::Bite::Email
71
73
  end
72
74
 
73
75
  if (readcursor & Indicators[:'message-rfc822']) == 0
74
- # Beginning of the original message part
76
+ # Beginning of the original message part(message/rfc822)
75
77
  if e.start_with?(StartingOf[:rfc822][0])
76
78
  readcursor |= Indicators[:'message-rfc822']
77
79
  next
@@ -79,60 +81,49 @@ module Sisimai::Bite::Email
79
81
  end
80
82
 
81
83
  if readcursor & Indicators[:'message-rfc822'] > 0
82
- # Before "message/rfc822"
84
+ # message/delivery-status part
83
85
  next if e.empty?
84
86
  v = dscontents[-1]
85
87
 
86
- if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
87
- # Final-Recipient: RFC822; kijitora@example.jp
88
- if v['recipient']
89
- # There are multiple recipient addresses in the message body.
90
- dscontents << Sisimai::Bite.DELIVERYSTATUS
91
- v = dscontents[-1]
92
- end
93
- v['recipient'] = cv[1]
94
- recipients += 1
95
-
96
- elsif cv = e.match(/\AX-Actual-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/) ||
97
- e.match(/\AOriginal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
98
- # X-Actual-Recipient: RFC822; kijitora@example.co.jp
99
- # Original-Recipient: rfc822;kijitora@example.co.jp
100
- v['alias'] = cv[1]
101
-
102
- elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
103
- # Action: failed
104
- v['action'] = cv[1].downcase
105
-
106
- elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
107
- # Status: 5.1.1
108
- v['status'] = cv[1]
109
-
110
- elsif cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
111
- # Reporting-MTA: dns; mx.example.jp
112
- v['lhost'] = cv[1].downcase
113
-
114
- elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
115
- # Remote-MTA: DNS; mx.example.jp
116
- v['rhost'] = cv[1].downcase
117
-
118
- elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
119
- # Last-Attempt-Date: Fri, 14 Feb 2014 12:30:08 -0500
120
- v['date'] = cv[1]
121
- else
122
- # Get an error message from Diagnostic-Code: field
123
- if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
88
+ if f = Sisimai::RFC1894.match(e)
89
+ # "e" matched with any field defined in RFC3464
90
+ next unless o = Sisimai::RFC1894.field(e)
91
+ v = dscontents[-1]
92
+
93
+ if o[-1] == 'addr'
94
+ # Final-Recipient: rfc822; kijitora@example.jp
95
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
96
+ if o[0] == 'final-recipient'
97
+ # Final-Recipient: rfc822; kijitora@example.jp
98
+ if v['recipient']
99
+ # There are multiple recipient addresses in the message body.
100
+ dscontents << Sisimai::Bite.DELIVERYSTATUS
101
+ v = dscontents[-1]
102
+ end
103
+ v['recipient'] = o[2]
104
+ recipients += 1
105
+ else
106
+ # X-Actual-Recipient: rfc822; kijitora@example.co.jp
107
+ v['alias'] = o[2]
108
+ end
109
+ elsif o[-1] == 'code'
124
110
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
125
- v['spec'] = cv[1].downcase
126
- v['diagnosis'] = cv[2]
127
-
128
- elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
129
- # Continued line of the value of Diagnostic-Code header
130
- v['diagnosis'] << ' ' << cv[1]
131
- havepassed[-1] = 'Diagnostic-Code: ' << e
111
+ v['spec'] = o[1]
112
+ v['diagnosis'] = o[2]
113
+ else
114
+ # Other DSN fields defined in RFC3464
115
+ next unless fieldtable.key?(o[0])
116
+ v[fieldtable[o[0]]] = o[2]
132
117
  end
118
+ else
119
+ # Continued line of the value of Diagnostic-Code field
120
+ next unless p.start_with?('Diagnostic-Code:')
121
+ next unless cv = e.match(/\A[ \t]+(.+)\z/)
122
+ v['diagnosis'] << ' ' << cv[1]
123
+ havepassed[-1] = 'Diagnostic-Code: ' << e
133
124
  end
134
125
  else
135
- # After "message/rfc822"
126
+ # message/rfc822 OR text/rfc822-headers part
136
127
  next unless recipients > 0
137
128
  next if (readcursor & Indicators['deliverystatus']) == 0
138
129