sisimai 4.22.3 → 4.22.4

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Benchmarks.mk +54 -0
  4. data/ChangeLog.md +23 -2
  5. data/Developers.mk +42 -35
  6. data/Makefile +10 -0
  7. data/README-JA.md +13 -13
  8. data/README.md +14 -14
  9. data/lib/sisimai.rb +12 -18
  10. data/lib/sisimai/address.rb +64 -82
  11. data/lib/sisimai/arf.rb +27 -42
  12. data/lib/sisimai/bite/email.rb +2 -4
  13. data/lib/sisimai/bite/email/activehunter.rb +12 -17
  14. data/lib/sisimai/bite/email/amazonses.rb +30 -48
  15. data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
  16. data/lib/sisimai/bite/email/aol.rb +27 -35
  17. data/lib/sisimai/bite/email/apachejames.rb +17 -28
  18. data/lib/sisimai/bite/email/bigfoot.rb +20 -33
  19. data/lib/sisimai/bite/email/biglobe.rb +15 -24
  20. data/lib/sisimai/bite/email/courier.rb +37 -61
  21. data/lib/sisimai/bite/email/domino.rb +19 -28
  22. data/lib/sisimai/bite/email/einsundeins.rb +20 -34
  23. data/lib/sisimai/bite/email/exchange2003.rb +25 -43
  24. data/lib/sisimai/bite/email/exchange2007.rb +15 -23
  25. data/lib/sisimai/bite/email/exim.rb +101 -120
  26. data/lib/sisimai/bite/email/ezweb.rb +28 -44
  27. data/lib/sisimai/bite/email/facebook.rb +26 -37
  28. data/lib/sisimai/bite/email/fml.rb +11 -20
  29. data/lib/sisimai/bite/email/gmx.rb +17 -27
  30. data/lib/sisimai/bite/email/google.rb +19 -29
  31. data/lib/sisimai/bite/email/gsuite.rb +39 -48
  32. data/lib/sisimai/bite/email/imailserver.rb +25 -39
  33. data/lib/sisimai/bite/email/interscanmss.rb +19 -26
  34. data/lib/sisimai/bite/email/kddi.rb +20 -33
  35. data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
  36. data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
  37. data/lib/sisimai/bite/email/mailru.rb +40 -59
  38. data/lib/sisimai/bite/email/mcafee.rb +21 -35
  39. data/lib/sisimai/bite/email/messagelabs.rb +23 -38
  40. data/lib/sisimai/bite/email/messagingserver.rb +15 -27
  41. data/lib/sisimai/bite/email/mfilter.rb +19 -28
  42. data/lib/sisimai/bite/email/mxlogic.rb +31 -49
  43. data/lib/sisimai/bite/email/notes.rb +16 -24
  44. data/lib/sisimai/bite/email/office365.rb +29 -38
  45. data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
  46. data/lib/sisimai/bite/email/outlook.rb +24 -36
  47. data/lib/sisimai/bite/email/postfix.rb +33 -42
  48. data/lib/sisimai/bite/email/qmail.rb +44 -59
  49. data/lib/sisimai/bite/email/receivingses.rb +28 -36
  50. data/lib/sisimai/bite/email/sendgrid.rb +28 -37
  51. data/lib/sisimai/bite/email/sendmail.rb +35 -51
  52. data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
  53. data/lib/sisimai/bite/email/userdefined.rb +17 -28
  54. data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
  55. data/lib/sisimai/bite/email/verizon.rb +31 -56
  56. data/lib/sisimai/bite/email/x1.rb +11 -18
  57. data/lib/sisimai/bite/email/x2.rb +11 -23
  58. data/lib/sisimai/bite/email/x3.rb +10 -19
  59. data/lib/sisimai/bite/email/x4.rb +46 -65
  60. data/lib/sisimai/bite/email/x5.rb +26 -37
  61. data/lib/sisimai/bite/email/yahoo.rb +11 -19
  62. data/lib/sisimai/bite/email/yandex.rb +19 -30
  63. data/lib/sisimai/bite/email/zoho.rb +21 -30
  64. data/lib/sisimai/bite/json.rb +1 -2
  65. data/lib/sisimai/bite/json/amazonses.rb +20 -25
  66. data/lib/sisimai/bite/json/sendgrid.rb +1 -1
  67. data/lib/sisimai/data.rb +36 -55
  68. data/lib/sisimai/data/json.rb +3 -3
  69. data/lib/sisimai/data/yaml.rb +1 -1
  70. data/lib/sisimai/datetime.rb +5 -21
  71. data/lib/sisimai/mail.rb +4 -6
  72. data/lib/sisimai/mail/maildir.rb +1 -1
  73. data/lib/sisimai/mda.rb +41 -44
  74. data/lib/sisimai/message.rb +2 -3
  75. data/lib/sisimai/message/email.rb +42 -52
  76. data/lib/sisimai/message/json.rb +7 -7
  77. data/lib/sisimai/mime.rb +25 -23
  78. data/lib/sisimai/order/email.rb +2 -2
  79. data/lib/sisimai/order/json.rb +2 -7
  80. data/lib/sisimai/reason.rb +41 -46
  81. data/lib/sisimai/reason/blocked.rb +60 -71
  82. data/lib/sisimai/reason/contenterror.rb +4 -8
  83. data/lib/sisimai/reason/delivered.rb +1 -3
  84. data/lib/sisimai/reason/exceedlimit.rb +10 -20
  85. data/lib/sisimai/reason/expired.rb +5 -9
  86. data/lib/sisimai/reason/feedback.rb +1 -3
  87. data/lib/sisimai/reason/filtered.rb +19 -38
  88. data/lib/sisimai/reason/hasmoved.rb +5 -8
  89. data/lib/sisimai/reason/hostunknown.rb +11 -18
  90. data/lib/sisimai/reason/mailboxfull.rb +14 -24
  91. data/lib/sisimai/reason/mailererror.rb +3 -5
  92. data/lib/sisimai/reason/mesgtoobig.rb +15 -25
  93. data/lib/sisimai/reason/networkerror.rb +8 -10
  94. data/lib/sisimai/reason/norelaying.rb +9 -14
  95. data/lib/sisimai/reason/notaccept.rb +9 -21
  96. data/lib/sisimai/reason/onhold.rb +3 -8
  97. data/lib/sisimai/reason/policyviolation.rb +8 -10
  98. data/lib/sisimai/reason/rejected.rb +36 -49
  99. data/lib/sisimai/reason/securityerror.rb +11 -13
  100. data/lib/sisimai/reason/spamdetected.rb +23 -37
  101. data/lib/sisimai/reason/suspend.rb +9 -10
  102. data/lib/sisimai/reason/syntaxerror.rb +3 -4
  103. data/lib/sisimai/reason/systemerror.rb +7 -9
  104. data/lib/sisimai/reason/systemfull.rb +2 -4
  105. data/lib/sisimai/reason/toomanyconn.rb +17 -30
  106. data/lib/sisimai/reason/undefined.rb +1 -3
  107. data/lib/sisimai/reason/userunknown.rb +28 -38
  108. data/lib/sisimai/reason/vacation.rb +4 -6
  109. data/lib/sisimai/reason/virusdetected.rb +4 -6
  110. data/lib/sisimai/rfc2606.rb +1 -2
  111. data/lib/sisimai/rfc3464.rb +87 -101
  112. data/lib/sisimai/rfc3834.rb +29 -39
  113. data/lib/sisimai/rfc5322.rb +17 -24
  114. data/lib/sisimai/rhost.rb +10 -7
  115. data/lib/sisimai/rhost/exchangeonline.rb +124 -255
  116. data/lib/sisimai/rhost/franceptt.rb +2 -2
  117. data/lib/sisimai/rhost/godaddy.rb +12 -25
  118. data/lib/sisimai/rhost/googleapps.rb +82 -183
  119. data/lib/sisimai/smtp.rb +4 -4
  120. data/lib/sisimai/smtp/error.rb +8 -8
  121. data/lib/sisimai/smtp/reply.rb +1 -1
  122. data/lib/sisimai/smtp/status.rb +1 -0
  123. data/lib/sisimai/string.rb +5 -7
  124. data/lib/sisimai/version.rb +1 -1
  125. data/set-of-emails/README.md +1 -1
  126. data/set-of-emails/maildir/bsd/README.md +50 -50
  127. data/sisimai-java.gemspec +1 -1
  128. data/sisimai.gemspec +1 -1
  129. metadata +5 -5
  130. data/lib/sisimai/skeleton.rb +0 -43
@@ -7,28 +7,15 @@ module Sisimai::Bite::Email
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/InterScanMSS.pm
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :from => %r/InterScan MSS/,
12
- :received => %r/[ ][(]InterScanMSS[)][ ]with[ ]/,
13
- :subject => [
14
- 'Mail could not be delivered',
15
- # メッセージを配信できません。
16
- '=?iso-2022-jp?B?GyRCJWElQyU7ITwlOCRyR1s/LiRHJC0kXiQ7JHMhIxsoQg==?=',
17
- # メール配信に失敗しました
18
- '=?iso-2022-jp?B?GyRCJWEhPCVrR1s/LiRLPDpHVCQ3JF4kNyQ/GyhCDQo=?=',
19
- ],
20
- }.freeze
21
- Re1 = {
22
- :begin => %r|\AContent-type: text/plain|,
23
- :rfc822 => %r|\AContent-type: message/rfc822|,
24
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
25
- }.freeze
26
10
  Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ message: ['Content-type: text/plain'],
13
+ rfc822: ['Content-type: message/rfc822'],
14
+ }.freeze
27
15
 
28
16
  def description; return 'Trend Micro InterScan Messaging Security Suite'; end
29
17
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
30
18
  def headerlist; return []; end
31
- def pattern; return Re0; end
32
19
 
33
20
  # Parse bounce messages from InterScanMSS
34
21
  # @param [Hash] mhead Message headers of a bounce email
@@ -45,9 +32,17 @@ module Sisimai::Bite::Email
45
32
  return nil unless mhead
46
33
  return nil unless mbody
47
34
 
48
- match = 0
49
- match += 1 if mhead['from'] =~ Re0[:from]
50
- match += 1 if Re0[:subject].find { |a| mhead['subject'] == a }
35
+ # :received => %r/[ ][(]InterScanMSS[)][ ]with[ ]/,
36
+ match = 0
37
+ tryto = [
38
+ 'Mail could not be delivered',
39
+ # メッセージを配信できません。
40
+ '=?iso-2022-jp?B?GyRCJWElQyU7ITwlOCRyR1s/LiRHJC0kXiQ7JHMhIxsoQg==?=',
41
+ # メール配信に失敗しました
42
+ '=?iso-2022-jp?B?GyRCJWEhPCVrR1s/LiRLPDpHVCQ3JF4kNyQ/GyhCDQo=?=',
43
+ ]
44
+ match += 1 if mhead['from'].include?('InterScan MSS')
45
+ match += 1 if tryto.find { |a| mhead['subject'] == a }
51
46
  return nil if match.zero?
52
47
 
53
48
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -58,10 +53,10 @@ module Sisimai::Bite::Email
58
53
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
59
54
  v = nil
60
55
 
61
- hasdivided.each do |e|
56
+ while e = hasdivided.shift do
62
57
  if readcursor.zero?
63
58
  # Beginning of the bounce message or delivery status part
64
- if e =~ Re1[:begin]
59
+ if e.start_with?(StartingOf[:message][0])
65
60
  readcursor |= Indicators[:deliverystatus]
66
61
  next
67
62
  end
@@ -69,7 +64,7 @@ module Sisimai::Bite::Email
69
64
 
70
65
  if (readcursor & Indicators[:'message-rfc822']).zero?
71
66
  # Beginning of the original message part
72
- if e =~ Re1[:rfc822]
67
+ if e.start_with?(StartingOf[:rfc822][0])
73
68
  readcursor |= Indicators[:'message-rfc822']
74
69
  next
75
70
  end
@@ -83,7 +78,6 @@ module Sisimai::Bite::Email
83
78
  next
84
79
  end
85
80
  rfc822list << e
86
-
87
81
  else
88
82
  # Before "message/rfc822"
89
83
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -113,7 +107,6 @@ module Sisimai::Bite::Email
113
107
  elsif cv = e.match(/\AReceived[ ]+[>]{3}[ ]+(\d{3}[ ]+.+)\z/)
114
108
  # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
115
109
  v['diagnosis'] = cv[1]
116
-
117
110
  else
118
111
  # Error message in non-English
119
112
  if cv = e.match(/[ ][>]{3}[ ]([A-Z]{4})/)
@@ -128,8 +121,8 @@ module Sisimai::Bite::Email
128
121
  end
129
122
  end
130
123
  return nil if recipients.zero?
131
- require 'sisimai/string'
132
124
 
125
+ require 'sisimai/string'
133
126
  dscontents.map do |e|
134
127
  e['agent'] = self.smtpagent
135
128
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -6,33 +6,24 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/KDDI.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :'from' => %r/no-reply[@].+[.]dion[.]ne[.]jp/,
11
- :'reply-to' => %r/\Afrom[ \t]+\w+[.]auone[-]net[.]jp[ \t]/,
12
- :'received' => %r/\Afrom[ ](?:.+[.])?ezweb[.]ne[.]jp[ ]/,
13
- :'message-id' => %r/[@].+[.]ezweb[.]ne[.]jp[>]\z/,
14
- }.freeze
15
- Re1 = {
16
- :begin => %r/\AYour[ ]mail[ ](?:
9
+ Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = { rfc822: ['Content-Type: message/rfc822'] }.freeze
11
+ MarkingsOf = {
12
+ message: %r/\AYour[ ]mail[ ](?:
17
13
  sent[ ]on:?[ ][A-Z][a-z]{2}[,]
18
14
  |attempted[ ]to[ ]be[ ]delivered[ ]on:?[ ][A-Z][a-z]{2}[,]
19
15
  )
20
16
  /x,
21
- :rfc822 => %r|\AContent-Type: message/rfc822\z|,
22
- :error => %r/Could not be delivered to:? /,
23
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
24
17
  }.freeze
25
- ReFailure = {
26
- mailboxfull: %r/As[ ]their[ ]mailbox[ ]is[ ]full/x,
27
- norelaying: %r/Due[ ]to[ ]the[ ]following[ ]SMTP[ ]relay[ ]error/x,
28
- hostunknown: %r/As[ ]the[ ]remote[ ]domain[ ]doesnt[ ]exist/x,
18
+ ReFailures = {
19
+ mailboxfull: %r/As their mailbox is full/,
20
+ norelaying: %r/Due to the following SMTP relay error/,
21
+ hostunknown: %r/As the remote domain doesnt exist/,
29
22
  }.freeze
30
- Indicators = Sisimai::Bite::Email.INDICATORS
31
23
 
32
24
  def description; return 'au by KDDI: http://www.au.kddi.com'; end
33
25
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
34
26
  def headerlist; return []; end
35
- def pattern; return Re0; end
36
27
 
37
28
  # Parse bounce messages from au by KDDI
38
29
  # @param [Hash] mhead Message headers of a bounce email
@@ -49,15 +40,15 @@ module Sisimai::Bite::Email
49
40
  return nil unless mhead
50
41
  return nil unless mbody
51
42
 
43
+ # :'message-id' => %r/[@].+[.]ezweb[.]ne[.]jp[>]\z/,
52
44
  match = 0
53
- match += 1 if mhead['from'] =~ Re0[:from]
54
- match += 1 if mhead['reply-to'] && mhead['reply-to'] =~ Re0[:'reply-to']
55
- match += 1 if mhead['received'].find { |a| a =~ Re0[:received] }
45
+ match += 1 if mhead['from'] =~ /no-reply[@].+[.]dion[.]ne[.]jp/
46
+ match += 1 if mhead['reply-to'].to_s == 'no-reply@app.auone-net.jp'
47
+ match += 1 if mhead['received'].find { |a| a.include?('ezweb.ne.jp (') }
56
48
  return nil if match.zero?
57
49
 
58
50
  require 'sisimai/string'
59
51
  require 'sisimai/address'
60
-
61
52
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
62
53
  hasdivided = mbody.split("\n")
63
54
  rfc822list = [] # (Array) Each line in message/rfc822 part string
@@ -66,10 +57,10 @@ module Sisimai::Bite::Email
66
57
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
67
58
  v = nil
68
59
 
69
- hasdivided.each do |e|
60
+ while e = hasdivided.shift do
70
61
  if readcursor.zero?
71
62
  # Beginning of the bounce message or delivery status part
72
- if e =~ Re1[:begin]
63
+ if e =~ MarkingsOf[:message]
73
64
  readcursor |= Indicators[:deliverystatus]
74
65
  next
75
66
  end
@@ -77,7 +68,7 @@ module Sisimai::Bite::Email
77
68
 
78
69
  if (readcursor & Indicators[:'message-rfc822']).zero?
79
70
  # Beginning of the original message part
80
- if e =~ Re1[:rfc822]
71
+ if e == StartingOf[:rfc822][0]
81
72
  readcursor |= Indicators[:'message-rfc822']
82
73
  next
83
74
  end
@@ -91,7 +82,6 @@ module Sisimai::Bite::Email
91
82
  next
92
83
  end
93
84
  rfc822list << e
94
-
95
85
  else
96
86
  # Before "message/rfc822"
97
87
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -117,27 +107,24 @@ module Sisimai::Bite::Email
117
107
  elsif cv = e.match(/Your mail sent on: (.+)\z/)
118
108
  # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
119
109
  v['date'] = cv[1]
120
-
121
110
  else
122
111
  # As their mailbox is full.
123
112
  v['diagnosis'] ||= ''
124
- v['diagnosis'] += e + ' ' if e =~ /\A[ \t]+/
113
+ v['diagnosis'] << e + ' ' if e.start_with?(' ', "\t")
125
114
  end
126
115
  end
127
116
  end
128
-
129
117
  return nil if recipients.zero?
130
- require 'sisimai/smtp/status'
131
118
 
119
+ require 'sisimai/smtp/status'
132
120
  dscontents.map do |e|
133
121
  e['agent'] = self.smtpagent
134
122
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
135
123
 
136
- if mhead['x-spasign'] && mhead['x-spasign'] == 'NG'
124
+ if mhead['x-spasign'].to_s == 'NG'
137
125
  # Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by KDDI)
138
126
  # Filtered recipient returns message that include 'X-SPASIGN' header
139
127
  e['reason'] = 'filtered'
140
-
141
128
  else
142
129
  if e['command'] == 'RCPT'
143
130
  # set "userunknown" when the remote server rejected after RCPT
@@ -145,9 +132,9 @@ module Sisimai::Bite::Email
145
132
  e['reason'] = 'userunknown'
146
133
  else
147
134
  # SMTP command is not RCPT
148
- ReFailure.each_key do |r|
135
+ ReFailures.each_key do |r|
149
136
  # Verify each regular expression of session errors
150
- next unless e['diagnosis'] =~ ReFailure[r]
137
+ next unless e['diagnosis'] =~ ReFailures[r]
151
138
  e['reason'] = r.to_s
152
139
  break
153
140
  end
@@ -6,22 +6,16 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/MailFoundry.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :subject => %r/\AMessage delivery has failed\z/,
11
- :received => %r/[(]MAILFOUNDRY[)] id /,
12
- }.freeze
13
- Re1 = {
14
- :begin => %r/\AThis is a MIME encoded message\z/,
15
- :error => %r/\ADelivery failed for the following reason:\z/,
16
- :rfc822 => %r|\AContent-Type: message/rfc822\z|,
17
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
18
- }.freeze
19
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['This is a MIME encoded message'],
12
+ rfc822: ['Content-Type: message/rfc822'],
13
+ error: ['Delivery failed for the following reason:'],
14
+ }.freeze
20
15
 
21
16
  def description; return 'MailFoundry'; end
22
17
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
23
18
  def headerlist; return []; end
24
- def pattern; return Re0; end
25
19
 
26
20
  # Parse bounce messages from MailFoundry
27
21
  # @param [Hash] mhead Message headers of a bounce email
@@ -37,8 +31,8 @@ module Sisimai::Bite::Email
37
31
  def scan(mhead, mbody)
38
32
  return nil unless mhead
39
33
  return nil unless mbody
40
- return nil unless mhead['subject'] =~ Re0[:subject]
41
- return nil unless mhead['received'].find { |a| a =~ Re0[:received] }
34
+ return nil unless mhead['subject'] == 'Message delivery has failed'
35
+ return nil unless mhead['received'].find { |a| a.include?('(MAILFOUNDRY) id ') }
42
36
 
43
37
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
44
38
  hasdivided = mbody.split("\n")
@@ -48,10 +42,10 @@ module Sisimai::Bite::Email
48
42
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
49
43
  v = nil
50
44
 
51
- hasdivided.each do |e|
45
+ while e = hasdivided.shift do
52
46
  if readcursor.zero?
53
47
  # Beginning of the bounce message or delivery status part
54
- if e =~ Re1[:begin]
48
+ if e == StartingOf[:message][0]
55
49
  readcursor |= Indicators[:deliverystatus]
56
50
  next
57
51
  end
@@ -59,7 +53,7 @@ module Sisimai::Bite::Email
59
53
 
60
54
  if (readcursor & Indicators[:'message-rfc822']).zero?
61
55
  # Beginning of the original message part
62
- if e =~ Re1[:rfc822]
56
+ if e == StartingOf[:rfc822][0]
63
57
  readcursor |= Indicators[:'message-rfc822']
64
58
  next
65
59
  end
@@ -73,7 +67,6 @@ module Sisimai::Bite::Email
73
67
  next
74
68
  end
75
69
  rfc822list << e
76
-
77
70
  else
78
71
  # Before "message/rfc822"
79
72
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -95,29 +88,26 @@ module Sisimai::Bite::Email
95
88
  end
96
89
  v['recipient'] = cv[1]
97
90
  recipients += 1
98
-
99
91
  else
100
92
  # Error message
101
- if e =~ Re1[:error]
93
+ if e == StartingOf[:error][0]
102
94
  # Delivery failed for the following reason:
103
95
  v['diagnosis'] = e
104
-
105
96
  else
106
97
  # Detect error message
107
98
  next if e.empty?
108
99
  next if v['diagnosis'].nil? || v['diagnosis'].empty?
109
- next if e =~ /\A[-]+/
100
+ next if e.start_with?('-')
110
101
 
111
102
  # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
112
- v['diagnosis'] ||= ''
113
- v['diagnosis'] += ' ' + e
103
+ v['diagnosis'] << ' ' << e
114
104
  end
115
105
  end
116
106
  end
117
107
  end
118
108
  return nil if recipients.zero?
119
- require 'sisimai/string'
120
109
 
110
+ require 'sisimai/string'
121
111
  dscontents.map do |e|
122
112
  e['agent'] = self.smtpagent
123
113
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -7,22 +7,16 @@ module Sisimai::Bite::Email
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/MailMarshalSMTP.pm
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :subject => %r/\AUndeliverable Mail: ["]/,
12
- }.freeze
13
- Re1 = {
14
- :begin => %r/\AYour message:\z/,
15
- :rfc822 => nil,
16
- :error => %r/\ACould not be delivered because of\z/,
17
- :rcpts => %r/\AThe following recipients were affected:/,
18
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
19
- }.freeze
20
10
  Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ message: ['Your message:'],
13
+ error: ['Could not be delivered because of'],
14
+ rcpts: ['The following recipients were affected:'],
15
+ }.freeze
21
16
 
22
17
  def description; return 'Trustwave Secure Email Gateway'; end
23
18
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
24
19
  def headerlist; return ['X-Mailer']; end
25
- def pattern; return Re0; end
26
20
 
27
21
  # Parse bounce messages from MailMarshalSMTP
28
22
  # @param [Hash] mhead Message headers of a bounce email
@@ -38,7 +32,7 @@ module Sisimai::Bite::Email
38
32
  def scan(mhead, mbody)
39
33
  return nil unless mhead
40
34
  return nil unless mbody
41
- return nil unless mhead['subject'] =~ Re0[:subject]
35
+ return nil unless mhead['subject'].start_with?('Undeliverable Mail: "')
42
36
 
43
37
  require 'sisimai/mime'
44
38
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -54,15 +48,15 @@ module Sisimai::Bite::Email
54
48
  boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
55
49
  regularexp = if boundary00.size > 0
56
50
  # Convert to regular expression
57
- Regexp.new('\A' + Regexp.escape('--' + boundary00 + '--') + '\z')
51
+ Regexp.new('\A' << Regexp.escape('--' << boundary00 << '--') << '\z')
58
52
  else
59
53
  regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
60
54
  end
61
55
 
62
- hasdivided.each do |e|
56
+ while e = hasdivided.shift do
63
57
  if readcursor.zero?
64
58
  # Beginning of the bounce message or delivery status part
65
- if e =~ Re1[:begin]
59
+ if e == StartingOf[:message][0]
66
60
  readcursor |= Indicators[:deliverystatus]
67
61
  next
68
62
  end
@@ -84,7 +78,6 @@ module Sisimai::Bite::Email
84
78
  next
85
79
  end
86
80
  rfc822list << e
87
-
88
81
  else
89
82
  # Before "message/rfc822"
90
83
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -112,21 +105,19 @@ module Sisimai::Bite::Email
112
105
  end
113
106
  v['recipient'] = cv[1]
114
107
  recipients += 1
115
-
116
108
  else
117
109
  # Get error message lines
118
- if e =~ Re1[:error]
110
+ if e == StartingOf[:error][0]
119
111
  # Could not be delivered because of
120
112
  #
121
113
  # 550 5.1.1 User unknown
122
114
  v['diagnosis'] = e
123
115
 
124
- elsif v['diagnosis'] && v['diagnosis'].size > 0 && endoferror == false
116
+ elsif v['diagnosis'].to_s.size > 0 && endoferror == false
125
117
  # Append error messages
126
- endoferror = true if e =~ Re1[:rcpts]
118
+ endoferror = true if e.start_with?(StartingOf[:rcpts][0])
127
119
  next if endoferror
128
- v['diagnosis'] += ' ' + e
129
-
120
+ v['diagnosis'] << ' ' << e
130
121
  else
131
122
  # Additional Information
132
123
  # ======================
@@ -140,7 +131,7 @@ module Sisimai::Bite::Email
140
131
  # Original Sender: <originalsender@example.com>
141
132
  # Use this line instead of "From" header of the original
142
133
  # message.
143
- rfc822list << sprintf('From: %s', cv[1])
134
+ rfc822list << ('From: ' << cv[1])
144
135
 
145
136
  elsif cv = e.match(/\ASender-MTA:[ \t]+[<](.+)[>]\z/)
146
137
  # Sender-MTA: <10.11.12.13>
@@ -155,8 +146,8 @@ module Sisimai::Bite::Email
155
146
  end
156
147
  end
157
148
  return nil if recipients.zero?
158
- require 'sisimai/string'
159
149
 
150
+ require 'sisimai/string'
160
151
  dscontents.map do |e|
161
152
  e['agent'] = self.smtpagent
162
153
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -7,36 +7,19 @@ module Sisimai::Bite::Email
7
7
  # Based on Sisimai::Bite::Email::Exim
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- # Message-Id: <E1P1YNN-0003AD-Ga@*.mail.ru>
12
- :'message-id' => %r/\A[<]\w+[-]\w+[-]\w+[@].*mail[.]ru[>]\z/,
13
- :'from' => %r/[<]?mailer-daemon[@].*mail[.]ru[>]?/i,
14
- :'subject' => %r{(?:
15
- Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
16
- |Warning:[ ]message[ ].+[ ]delayed[ ]+
17
- |Delivery[ ]Status[ ]Notification
18
- |Mail[ ]failure
19
- |Message[ ]frozen
20
- |error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
21
- )
22
- }x,
23
- }.freeze
24
- Re1 = {
25
- :rfc822 => %r/\A------ This is a copy of the message.+headers[.] ------\z/,
26
- :begin => %r/\AThis message was created automatically by mail delivery software[.]/,
27
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
10
+ Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ message: ['This message was created automatically by mail delivery software.'],
13
+ rfc822: ['------ This is a copy of the message, including all the headers. ------'],
28
14
  }.freeze
29
- ReCommand = [
15
+
16
+ ReCommands = [
30
17
  %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
31
18
  %r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
32
19
  ].freeze
33
- ReFailure = {
34
- expired: %r{(?:
35
- retry[ ]timeout[ ]exceeded
36
- |No[ ]action[ ]is[ ]required[ ]on[ ]your[ ]part
37
- )
38
- }x,
39
- userunknown: %r/user[ ]not[ ]found/x,
20
+ ReFailures = {
21
+ expired: %r/(?:retry timeout exceeded|No action is required on your part)/,
22
+ userunknown: %r/user not found/,
40
23
  hostunknown: %r{(?>
41
24
  all[ ](?:
42
25
  host[ ]address[ ]lookups[ ]failed[ ]permanently
@@ -45,25 +28,19 @@ module Sisimai::Bite::Email
45
28
  |Unrouteable[ ]address
46
29
  )
47
30
  }x,
48
- mailboxfull: %r/(?:mailbox[ ]is[ ]full:?|error:[ ]quota[ ]exceed)/x,
49
- notaccept: %r{(?:
31
+ mailboxfull: %r/(?:mailbox is full:?|error: quota exceed)/,
32
+ notaccept: %r{(?:
50
33
  an[ ]MX[ ]or[ ]SRV[ ]record[ ]indicated[ ]no[ ]SMTP[ ]service
51
34
  |no[ ]host[ ]found[ ]for[ ]existing[ ]SMTP[ ]connection
52
35
  )
53
36
  }x,
54
- systemerror: %r{(?:
55
- delivery[ ]to[ ](?:file|pipe)[ ]forbidden
56
- |local[ ]delivery[ ]failed
57
- )
58
- }x,
59
- contenterror: %r/Too[ ]many[ ]["]Received["][ ]headers[ ]/x,
37
+ systemerror: %r/(?:delivery to (?:file|pipe) forbidden|local delivery failed)/,
38
+ contenterror: %r/Too many ["]Received["] headers /,
60
39
  }.freeze
61
- Indicators = Sisimai::Bite::Email.INDICATORS
62
40
 
63
41
  def description; return '@mail.ru: https://mail.ru'; end
64
42
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
65
43
  def headerlist; return ['X-Failed-Recipients']; end
66
- def pattern; return Re0; end
67
44
 
68
45
  # Parse bounce messages from @mail.ru
69
46
  # @param [Hash] mhead Message headers of a bounce email
@@ -79,9 +56,18 @@ module Sisimai::Bite::Email
79
56
  def scan(mhead, mbody)
80
57
  return nil unless mhead
81
58
  return nil unless mbody
82
- return nil unless mhead['from'] =~ Re0[:from]
83
- return nil unless mhead['subject'] =~ Re0[:subject]
84
- return nil unless mhead['message-id'] =~ Re0[:'message-id']
59
+
60
+ return nil unless mhead['from'] =~ /[<]?mailer-daemon[@].*mail[.]ru[>]?/i
61
+ return nil unless mhead['message-id'].end_with?('.mail.ru>')
62
+ return nil unless mhead['subject'] =~ %r{(?:
63
+ Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
64
+ |Warning:[ ]message[ ].+[ ]delayed[ ]+
65
+ |Delivery[ ]Status[ ]Notification
66
+ |Mail[ ]failure
67
+ |Message[ ]frozen
68
+ |error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
69
+ )
70
+ }x
85
71
 
86
72
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
87
73
  hasdivided = mbody.split("\n")
@@ -92,10 +78,10 @@ module Sisimai::Bite::Email
92
78
  localhost0 = '' # (String) Local MTA
93
79
  v = nil
94
80
 
95
- hasdivided.each do |e|
81
+ while e = hasdivided.shift do
96
82
  if readcursor.zero?
97
83
  # Beginning of the bounce message or delivery status part
98
- if e =~ Re1[:begin]
84
+ if e.start_with?(StartingOf[:message][0])
99
85
  readcursor |= Indicators[:deliverystatus]
100
86
  next
101
87
  end
@@ -103,7 +89,7 @@ module Sisimai::Bite::Email
103
89
 
104
90
  if (readcursor & Indicators[:'message-rfc822']).zero?
105
91
  # Beginning of the original message part
106
- if e =~ Re1[:rfc822]
92
+ if e == StartingOf[:rfc822][0]
107
93
  readcursor |= Indicators[:'message-rfc822']
108
94
  next
109
95
  end
@@ -118,7 +104,6 @@ module Sisimai::Bite::Email
118
104
  next
119
105
  end
120
106
  rfc822list << e
121
-
122
107
  else
123
108
  # Before "message/rfc822"
124
109
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -158,14 +143,13 @@ module Sisimai::Bite::Email
158
143
  # Error message
159
144
  next if e.empty?
160
145
  v['diagnosis'] ||= ''
161
- v['diagnosis'] += e + ' '
162
-
146
+ v['diagnosis'] << e + ' '
163
147
  else
164
148
  # Error message when email address above does not include '@'
165
149
  # and domain part.
166
- next unless e =~ /\A[ \t]{4}/
150
+ next unless e.start_with?(' ', "\t")
167
151
  v['alterrors'] ||= ''
168
- v['alterrors'] += e + ' '
152
+ v['alterrors'] << e + ' '
169
153
  end
170
154
  end
171
155
  end
@@ -178,7 +162,7 @@ module Sisimai::Bite::Email
178
162
  rcptinhead.each { |a| a.delete(' ') }
179
163
  recipients = rcptinhead.size
180
164
 
181
- rcptinhead.each do |e|
165
+ while e = rcptinhead.shift do
182
166
  # Insert each recipient address into dscontents
183
167
  dscontents[-1]['recipient'] = e
184
168
  next if dscontents.size == recipients
@@ -201,10 +185,10 @@ module Sisimai::Bite::Email
201
185
  # Set default values if each value is empty.
202
186
  e['lhost'] ||= localhost0
203
187
 
204
- if e['alterrors'] && e['alterrors'].size > 0
188
+ if e['alterrors'].to_s.size > 0
205
189
  # Copy alternative error message
206
190
  e['diagnosis'] ||= e['alterrors']
207
- if e['diagnosis'] =~ /\A[-]+/ || e['diagnosis'].end_with?('__')
191
+ if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
208
192
  # Override the value of diagnostic code message
209
193
  e['diagnosis'] = e['alterrors'] if e['alterrors'].size > 0
210
194
  end
@@ -221,16 +205,14 @@ module Sisimai::Bite::Email
221
205
  end
222
206
 
223
207
  unless e['rhost']
224
- if mhead['received'].size > 0
225
- # Get localhost and remote host name from Received header.
226
- e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop
227
- end
208
+ # Get localhost and remote host name from Received header.
209
+ e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop if mhead['received'].size > 0
228
210
  end
229
211
  end
230
212
 
231
213
  unless e['command']
232
214
  # Get the SMTP command name for the session
233
- ReCommand.each do |r|
215
+ ReCommands.each do |r|
234
216
  # Verify each regular expression of SMTP commands
235
217
  if cv = e['diagnosis'].match(r)
236
218
  e['command'] = cv[1].upcase
@@ -239,19 +221,18 @@ module Sisimai::Bite::Email
239
221
  end
240
222
 
241
223
  # Detect the reason of bounce
242
- if e['command'] =~ /\A(?:HELO|EHLO)\z/
224
+ if %w[HELO EHLO].index(e['command'])
243
225
  # HELO | Connected to 192.0.2.135 but my name was rejected.
244
226
  e['reason'] = 'blocked'
245
227
 
246
228
  elsif e['command'] == 'MAIL'
247
229
  # MAIL | Connected to 192.0.2.135 but sender was rejected.
248
230
  e['reason'] = 'rejected'
249
-
250
231
  else
251
232
  # Verify each regular expression of session errors
252
- ReFailure.each_key do |r|
233
+ ReFailures.each_key do |r|
253
234
  # Check each regular expression
254
- next unless e['diagnosis'] =~ ReFailure[r]
235
+ next unless e['diagnosis'] =~ ReFailures[r]
255
236
  e['reason'] = r.to_s
256
237
  break
257
238
  end