sisimai 4.25.6 → 4.25.11

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -3
  3. data/ANALYTICAL-PRECISION +1 -1
  4. data/Benchmarks.mk +1 -1
  5. data/ChangeLog.md +71 -2
  6. data/Developers.mk +2 -2
  7. data/Makefile +1 -1
  8. data/README-JA.md +16 -16
  9. data/README.md +16 -16
  10. data/Repository.mk +1 -1
  11. data/lib/sisimai.rb +3 -3
  12. data/lib/sisimai/address.rb +6 -3
  13. data/lib/sisimai/arf.rb +25 -21
  14. data/lib/sisimai/data.rb +8 -29
  15. data/lib/sisimai/datetime.rb +18 -17
  16. data/lib/sisimai/lhost/amazonses.rb +1 -1
  17. data/lib/sisimai/lhost/domino.rb +29 -4
  18. data/lib/sisimai/lhost/einsundeins.rb +1 -1
  19. data/lib/sisimai/lhost/exchange2007.rb +1 -1
  20. data/lib/sisimai/lhost/exim.rb +12 -8
  21. data/lib/sisimai/lhost/ezweb.rb +1 -1
  22. data/lib/sisimai/lhost/fml.rb +0 -2
  23. data/lib/sisimai/lhost/gsuite.rb +5 -0
  24. data/lib/sisimai/lhost/imailserver.rb +1 -1
  25. data/lib/sisimai/lhost/mailfoundry.rb +3 -4
  26. data/lib/sisimai/lhost/mailmarshalsmtp.rb +2 -2
  27. data/lib/sisimai/lhost/mxlogic.rb +1 -1
  28. data/lib/sisimai/lhost/notes.rb +1 -1
  29. data/lib/sisimai/lhost/office365.rb +1 -1
  30. data/lib/sisimai/lhost/postfix.rb +3 -10
  31. data/lib/sisimai/lhost/qmail.rb +7 -7
  32. data/lib/sisimai/lhost/sendgrid.rb +2 -2
  33. data/lib/sisimai/lhost/sendmail.rb +1 -1
  34. data/lib/sisimai/lhost/verizon.rb +4 -4
  35. data/lib/sisimai/lhost/x3.rb +4 -0
  36. data/lib/sisimai/lhost/x4.rb +8 -8
  37. data/lib/sisimai/lhost/x5.rb +7 -3
  38. data/lib/sisimai/mail.rb +2 -21
  39. data/lib/sisimai/mda.rb +2 -2
  40. data/lib/sisimai/message.rb +47 -83
  41. data/lib/sisimai/reason/blocked.rb +40 -26
  42. data/lib/sisimai/reason/exceedlimit.rb +4 -1
  43. data/lib/sisimai/reason/expired.rb +2 -0
  44. data/lib/sisimai/reason/filtered.rb +1 -0
  45. data/lib/sisimai/reason/hostunknown.rb +3 -0
  46. data/lib/sisimai/reason/mailererror.rb +1 -1
  47. data/lib/sisimai/reason/norelaying.rb +5 -0
  48. data/lib/sisimai/reason/notaccept.rb +2 -0
  49. data/lib/sisimai/reason/policyviolation.rb +4 -0
  50. data/lib/sisimai/reason/rejected.rb +5 -1
  51. data/lib/sisimai/reason/securityerror.rb +5 -6
  52. data/lib/sisimai/reason/spamdetected.rb +17 -15
  53. data/lib/sisimai/reason/suspend.rb +1 -0
  54. data/lib/sisimai/reason/systemerror.rb +2 -0
  55. data/lib/sisimai/reason/userunknown.rb +25 -21
  56. data/lib/sisimai/rfc1894.rb +24 -22
  57. data/lib/sisimai/rfc3464.rb +4 -5
  58. data/lib/sisimai/rfc3834.rb +1 -1
  59. data/lib/sisimai/rfc5322.rb +8 -4
  60. data/lib/sisimai/rhost.rb +6 -8
  61. data/lib/sisimai/rhost/cox.rb +112 -0
  62. data/lib/sisimai/rhost/exchangeonline.rb +8 -1
  63. data/lib/sisimai/rhost/googleapps.rb +4 -1
  64. data/lib/sisimai/rhost/spectrum.rb +73 -0
  65. data/lib/sisimai/smtp/error.rb +8 -6
  66. data/lib/sisimai/smtp/reply.rb +1 -1
  67. data/lib/sisimai/smtp/status.rb +1 -1
  68. data/lib/sisimai/time.rb +1 -2
  69. data/lib/sisimai/version.rb +1 -1
  70. data/set-of-emails/README.md +5 -4
  71. data/set-of-emails/maildir/bsd/arf-25.eml +61 -0
  72. data/set-of-emails/maildir/bsd/lhost-aol-04.eml +23 -23
  73. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +1 -2
  74. data/set-of-emails/maildir/bsd/lhost-exim-61.eml +40 -0
  75. data/set-of-emails/maildir/bsd/lhost-postfix-38.eml +1 -1
  76. data/set-of-emails/maildir/bsd/lhost-postfix-66.eml +80 -0
  77. data/set-of-emails/maildir/bsd/lhost-postfix-67.eml +80 -0
  78. data/set-of-emails/maildir/bsd/lhost-postfix-68.eml +82 -0
  79. data/set-of-emails/maildir/bsd/lhost-postfix-69.eml +80 -0
  80. data/set-of-emails/maildir/bsd/lhost-postfix-70.eml +87 -0
  81. data/set-of-emails/maildir/bsd/lhost-postfix-71.eml +81 -0
  82. data/set-of-emails/maildir/bsd/lhost-postfix-72.eml +81 -0
  83. data/set-of-emails/maildir/bsd/lhost-postfix-73.eml +79 -0
  84. data/set-of-emails/maildir/bsd/lhost-postfix-74.eml +83 -0
  85. data/set-of-emails/maildir/bsd/lhost-sendmail-08.eml +1 -1
  86. data/set-of-emails/maildir/bsd/lhost-sendmail-11.eml +1 -1
  87. data/set-of-emails/maildir/bsd/lhost-sendmail-57.eml +59 -0
  88. data/set-of-emails/maildir/bsd/lhost-sendmail-58.eml +70 -0
  89. data/set-of-emails/maildir/bsd/lhost-sendmail-59.eml +68 -0
  90. data/set-of-emails/maildir/bsd/lhost-x3-06.eml +53 -0
  91. data/set-of-emails/maildir/bsd/rhost-cox-01.eml +192 -0
  92. data/set-of-emails/maildir/bsd/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  93. data/set-of-emails/maildir/bsd/{rhost-exchange-online-02.eml → rhost-exchangeonline-02.eml} +0 -0
  94. data/set-of-emails/maildir/bsd/{rhost-exchange-online-03.eml → rhost-exchangeonline-03.eml} +0 -0
  95. data/set-of-emails/maildir/bsd/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  96. data/set-of-emails/maildir/bsd/{rhost-google-apps-02.eml → rhost-googleapps-02.eml} +0 -0
  97. data/set-of-emails/maildir/bsd/rhost-spectrum-01.eml +111 -0
  98. data/set-of-emails/maildir/dos/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  99. data/set-of-emails/maildir/dos/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  100. data/set-of-emails/maildir/mac/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  101. data/set-of-emails/maildir/mac/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  102. data/sisimai-java.gemspec +4 -4
  103. data/sisimai.gemspec +4 -4
  104. metadata +39 -20
@@ -25,17 +25,20 @@ module Sisimai
25
25
  'Sisimai::Reason::Rejected' => 'sisimai/reason/rejected',
26
26
  }
27
27
  Regex = %r{(?>
28
- .+[ ]user[ ]unknown
29
- |[#]5[.]1[.]1[ ]bad[ ]address
30
- |[<].+[>][ ]not[ ]found
31
- |[<].+[@].+[>][.][.][.][ ]blocked[ ]by[ ]
28
+ [#]5[.]1[.]1[ ]bad[ ]address
29
+ |[<][^ ]+[>][ ]not[ ]found
30
+ |[<][^ ]+[@][^ ]+[>][.][.][.][ ]blocked[ ]by[ ]
31
+ |550[ ]address[ ]invalid
32
32
  |5[.]0[.]0[.][ ]mail[ ]rejected[.]
33
33
  |5[.]1[.]0[ ]address[ ]rejected[.]
34
- |adresse[ ]d[ ]au[ ]moins[ ]un[ ]destinataire[ ]invalide.+[a-z]{3}.+(?:416|418)
34
+ |account[ ][^ ]+[ ]does[ ]not[ ]exist[ ]at[ ]the[ ]organization
35
+ |adresse[ ]d[ ]au[ ]moins[ ]un[ ]destinataire[ ]invalide[.][ ]invalid[ ]recipient[.][0-9a-z_]+41[68]
35
36
  |address[ ](?:does[ ]not[ ]exist|unknown)
37
+ |address[ ](?:does[ ]not[ ]exist|not[ ]present[ ]in[ ]directory|unknown)
36
38
  |archived[ ]recipient
37
39
  |bad[-_ ]recipient
38
40
  |can[']t[ ]accept[ ]user
41
+ |does[ ]not[ ]exist[.]
39
42
  |destination[ ](?:
40
43
  addresses[ ]were[ ]unknown
41
44
  |server[ ]rejected[ ]recipients
@@ -43,7 +46,7 @@ module Sisimai
43
46
  |email[ ]address[ ](?:does[ ]not[ ]exist|could[ ]not[ ]be[ ]found)
44
47
  |invalid[ ](?:
45
48
  address
46
- |mailbox:
49
+ |mailbox:?
47
50
  |mailbox[ ]path
48
51
  |recipient
49
52
  )
@@ -53,16 +56,17 @@ module Sisimai
53
56
  |an[ ]active[ ]address[ ]at[ ]this[ ]host
54
57
  )
55
58
  |mailbox[ ](?:
56
- .+[ ]does[ ]not[ ]exist
57
- |.+[@].+[ ]unavailable
59
+ [^ ]+[ ]does[ ]not[ ]exist
60
+ |[^ ]+[@][^ ]+[ ]unavailable
58
61
  |does[ ]not[ ]exist
59
62
  |invalid
60
63
  |is[ ](?:inactive|unavailable)
61
64
  |not[ ](?:present|found)
62
65
  |unavailable
63
66
  )
67
+ |nessun[ ]utente[ ]simile[ ]in[ ]questo[ ]indirizzo
64
68
  |no[ ](?:
65
- [ ].+[ ]in[ ]name[ ]directory
69
+ [ ][^ ]+[ ]in[ ]name[ ]directory
66
70
  |account[ ]by[ ]that[ ]name[ ]here
67
71
  |existe[ ](?:dicha[ ]persona|ese[ ]usuario[ ])
68
72
  |mail[ ]box[ ]available[ ]for[ ]this[ ]user
@@ -79,7 +83,7 @@ module Sisimai
79
83
  |user(?:[ ]here)?
80
84
  )
81
85
  |thank[ ]you[ ]rejected:[ ]account[ ]unavailable:
82
- |valid[ ]recipients[,][ ]bye # Microsoft
86
+ |valid[ ]recipients,[ ]bye
83
87
  )
84
88
  |non[- ]?existent[ ]user
85
89
  |not[ ](?:
@@ -87,15 +91,15 @@ module Sisimai
87
91
  |a[ ]local[ ]address
88
92
  |email[ ]addresses
89
93
  )
90
- |rcpt[ ][<].+[>][ ]does[ ]not[ ]exist
94
+ |rcpt[ ][<][^ ]+[>][ ]does[ ]not[ ]exist
91
95
  |recipient[ ]address[ ]rejected[.][ ][(]in[ ]reply[ ]to[ ]rcpt[ ]to[ ]command[)]
92
- |rece?ipient[ ](?:
93
- .+[ ]was[ ]not[ ]found[ ]in
96
+ |recipient[ ](?:
97
+ [^ ]+[ ]was[ ]not[ ]found[ ]in
94
98
  |address[ ]rejected:[ ](?:
95
99
  access[ ]denied
96
100
  |invalid[ ]user
97
- |user[ ].+[ ]does[ ]not[ ]exist
98
- |user[ ]unknown[ ]in[ ].+[ ]table
101
+ |user[ ][^ ]+[ ]does[ ]not[ ]exist
102
+ |user[ ]unknown[ ]in[ ][^ ]+[ ]table
99
103
  |unknown[ ]user
100
104
  )
101
105
  |does[ ]not[ ]exist(?:[ ]on[ ]this[ ]system)?
@@ -104,9 +108,8 @@ module Sisimai
104
108
  |unknown
105
109
  )
106
110
  |requested[ ]action[ ]not[ ]taken:[ ]mailbox[ ]unavailable
107
- |resolver[.]adr[.]recip(?:ient)notfound
108
- |said:[ ]550[-[ ]]5[.]1[.]1[ ].+[ ]user[ ]unknown[ ]
109
- |smtp[ ]error[ ]from[ ]remote[ ]mail[ ]server[ ]after[ ]end[ ]of[ ]data:[ ]553.+does[ ]not[ ]exist
111
+ |resolver[.]adr[.]recipient notfound
112
+ |said:[ ]550[-[ ]]5[.]1[.]1[ ][^ ]+[ ]user[ ]unknown[ ]
110
113
  |sorry,[ ](?:
111
114
  user[ ]unknown
112
115
  |badrcptto
@@ -122,7 +125,7 @@ module Sisimai
122
125
  address[ ]no[ ]longer[ ]accepts[ ]mail
123
126
  |email[ ]address[ ]is[ ]wrong[ ]or[ ]no[ ]longer[ ]valid
124
127
  |spectator[ ]does[ ]not[ ]exist
125
- |user[ ]doesn[']?t[ ]have[ ]a[ ].+[ ]account
128
+ |user[ ]doesn[']?t[ ]have[ ]a[ ][^ ]+[ ]account
126
129
  )
127
130
  |unknown[ ](?:
128
131
  e[-]?mail[ ]address
@@ -132,13 +135,14 @@ module Sisimai
132
135
  |user
133
136
  )
134
137
  |user[ ](?:
135
- .+[ ]was[ ]not[ ]found
136
- |.+[ ]does[ ]not[ ]exist
138
+ [^ ]+[ ]was[ ]not[ ]found
139
+ |[^ ]+[ ]does[ ]not[ ]exist
137
140
  |does[ ]not[ ]exist
138
141
  |missing[ ]home[ ]directory
139
142
  |not[ ](?:active|exist|found|known)
140
143
  |unknown
141
144
  )
145
+ |utilisateur[ ]inconnu[ ]!
142
146
  |vdeliver:[ ]invalid[ ]or[ ]unknown[ ]virtual[ ]user
143
147
  |your[ ]envelope[ ]recipient[ ]is[ ]in[ ]my[ ]badrcptto[ ]list
144
148
  )
@@ -38,14 +38,14 @@ module Sisimai
38
38
  'addr' => %r/\A((?:Original|Final|X-Actual)-Recipient):[ ]*(.+?);[ ]*(.+)/,
39
39
  'code' => %r/\A(Diagnostic-Code):[ ]*(.+?);[ ]*(.*)/,
40
40
  'date' => %r/\A((?:Arrival|Last-Attempt)-Date):[ ]*(.+)/,
41
- 'host' => %r/\A((?:Reporting|Received-From|Remote)-MTA):[ ]*(.+?);[ ]*(.+)/,
42
- 'list' => %r/\A(Action):[ ]*(failed|delayed|delivered|relayed|expanded|expired|failure)/i,
41
+ 'host' => %r/\A((?:Received-From|Remote|Reporting)-MTA):[ ]*(.+?);[ ]*(.+)/,
42
+ 'list' => %r/\A(Action):[ ]*(delayed|deliverable|delivered|expanded|expired|failed|failure|relayed)/i,
43
43
  'stat' => %r/\A(Status):[ ]*([245][.]\d+[.]\d+)/,
44
44
  'text' => %r/\A(X-Original-Message-ID):[ ]*(.+)/,
45
- #text: %r/\A(Original-Envelope-Id|Final-Log-ID):[ ]*(.+)/,
45
+ #'text' => %r/\A(Final-Log-ID|Original-Envelope-Id):[ ]*(.+)/,
46
46
  }.freeze
47
47
 
48
- Correction = { action: { 'failure' => 'failed', 'expired' => 'delayed' } }
48
+ Correction = { action: { 'deliverable' => 'delivered', 'expired' => 'delayed', 'failure' => 'failed' }}
49
49
  FieldGroup = {
50
50
  'original-recipient' => 'addr',
51
51
  'final-recipient' => 'addr',
@@ -86,8 +86,8 @@ module Sisimai
86
86
  # @since v4.25.0
87
87
  def match(argv0 = '')
88
88
  return nil if argv0.empty?
89
- return 1 if FieldNames[0].any? { |a| argv0.start_with?(a) }
90
- return 2 if FieldNames[1].any? { |a| argv0.start_with?(a) }
89
+ return 1 if FieldNames[0].any? { |a| argv0.start_with?(a) }
90
+ return 2 if FieldNames[1].any? { |a| argv0.start_with?(a) }
91
91
  return nil
92
92
  end
93
93
 
@@ -98,42 +98,44 @@ module Sisimai
98
98
  def field(argv0 = '')
99
99
  return nil if argv0.empty?
100
100
  group = FieldGroup[argv0.split(':',2).shift.downcase] || ''
101
- match = []
102
101
 
103
102
  return nil if group.empty?
104
103
  return nil unless CapturesOn[group]
105
104
 
105
+ table = ['', '', '', '']
106
+ match = false
106
107
  while cv = argv0.match(CapturesOn[group])
107
108
  # Try to match with each pattern of Per-Message field, Per-Recipient field
108
- # - 0: Field-Name
109
- # - 1: Sub Type: RFC822, DNS, X-Unix, and so on)
110
- # - 2: Value
111
- # - 3: Field Group(addr, code, date, host, stat, text)
112
- match[0] = cv[1].downcase
113
- match[3] = group
109
+ # - 0: Field-Name
110
+ # - 1: Sub Type: RFC822, DNS, X-Unix, and so on)
111
+ # - 2: Value
112
+ # - 3: Field Group(addr, code, date, host, stat, text)
113
+ match = true
114
+ table[0] = cv[1].downcase
115
+ table[3] = group
114
116
 
115
117
  if group == 'addr' || group == 'code' || group == 'host'
116
118
  # - Final-Recipient: RFC822; kijitora@nyaan.jp
117
119
  # - Diagnostic-Code: SMTP; 550 5.1.1 <kijitora@example.jp>... User Unknown
118
120
  # - Remote-MTA: DNS; mx.example.jp
119
- match[1] = cv[2].upcase
120
- match[2] = group == 'host' ? cv[3].downcase : cv[3]
121
- match[2] = '' if match[2] =~ /\A\s+\z/ # Remote-MTA: dns;
121
+ table[1] = cv[2].upcase
122
+ table[2] = group == 'host' ? cv[3].downcase : cv[3]
123
+ table[2] = '' if table[2] =~ /\A\s+\z/ # Remote-MTA: dns;
122
124
  else
123
125
  # - Action: failed
124
126
  # - Status: 5.2.2
125
- match[1] = ''
126
- match[2] = group == 'date' ? cv[2] : cv[2].downcase
127
+ table[1] = ''
128
+ table[2] = group == 'date' ? cv[2] : cv[2].downcase
127
129
 
128
130
  # Correct invalid value in Action field:
129
131
  break unless group == 'list'
130
- break unless Correction[:action][match[2]]
131
- match[2] = Correction[:action][match[2]]
132
+ break unless Correction[:action][table[2]]
133
+ table[2] = Correction[:action][table[2]]
132
134
  end
133
135
  break
134
136
  end
135
- return nil if match.empty?
136
- return match
137
+ return nil unless match
138
+ return table
137
139
  end
138
140
 
139
141
  end
@@ -98,12 +98,9 @@ module Sisimai
98
98
  # @return [Hash] Bounce data list and message/rfc822 part
99
99
  # @return [Nil] it failed to parse or the arguments are missing
100
100
  def make(mhead, mbody)
101
- require 'sisimai/mda'
102
-
103
101
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
104
102
  bodyslices = mbody.scrub('?').split("\n")
105
103
  readslices = ['']
106
- mdabounced = Sisimai::MDA.make(mhead, mbody)
107
104
  rfc822text = '' # (String) message/rfc822 part text
108
105
  maybealias = nil # (String) Original-Recipient Field
109
106
  blanklines = 0 # (Integer) The number of blank lines
@@ -177,7 +174,7 @@ module Sisimai
177
174
  maybealias = cv[2]
178
175
  else
179
176
  # Final-Recipient: ...
180
- x = v['recipienet'] || ''
177
+ x = v['recipient'] || ''
181
178
  y = Sisimai::Address.s3s4(cv[2])
182
179
  y = maybealias unless Sisimai::RFC5322.is_emailaddress(y)
183
180
 
@@ -287,7 +284,7 @@ module Sisimai
287
284
  elsif readslices[-2].start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
288
285
  # Continued line of the value of Diagnostic-Code header
289
286
  v['diagnosis'] << ' ' << cv[1]
290
- e = 'Diagnostic-Code: ' << e
287
+ readslices[-1] = 'Diagnostic-Code: ' << e
291
288
  else
292
289
  if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
293
290
  # 2.2.2 The Reporting-MTA DSN field
@@ -421,6 +418,8 @@ module Sisimai
421
418
  end
422
419
  return nil unless recipients > 0
423
420
 
421
+ require 'sisimai/mda'
422
+ mdabounced = Sisimai::MDA.make(mhead, mbody)
424
423
  dscontents.each do |e|
425
424
  # Set default values if each value is empty.
426
425
  connheader.each_key { |a| e[a] ||= connheader[a] || '' }
@@ -99,7 +99,7 @@ module Sisimai
99
99
  if mhead['content-type']
100
100
  # Get the boundary string and set regular expression for matching with
101
101
  # the boundary string.
102
- b0 = Sisimai::MIME.boundary(mhead['content-type'], 0)
102
+ b0 = Sisimai::MIME.boundary(mhead['content-type'], 0) || ''
103
103
  MarkingsOf[:boundary] = %r/\A\Q#{b0}\E\z/ unless b0.empty?
104
104
  end
105
105
 
@@ -64,9 +64,8 @@ module Sisimai
64
64
  # Fields that might be long
65
65
  # @return [Hash] Long filed(email header) list
66
66
  def LONGFIELDS
67
- return { 'to' => 1, 'from' => 1, 'subject' => 1, 'message-id' => 1 }
67
+ return { 'to' => true, 'from' => true, 'subject' => true, 'message-id' => true }
68
68
  end
69
- LongHeaders = Sisimai::RFC5322.LONGFIELDS
70
69
 
71
70
  # Check that the argument is an email address or not
72
71
  # @param [String] email Email address string
@@ -192,8 +191,13 @@ module Sisimai
192
191
  v[1] ||= ''
193
192
 
194
193
  unless v[1].empty?
195
- v[1].sub(/\A[\r\n\s]+/, '')
196
- v[1].sub(/\n\n.+\z/m, '')
194
+ # Remove blank lines, the message body of the original message, and append "\n" at the end
195
+ # of the original message headers
196
+ # 1. Remove leading blank lines
197
+ # 2. Remove text after the first blank line: \n\n
198
+ # 3. Append "\n" at the end of test block when the last character is not "\n"
199
+ v[1].sub!(/\A[\r\n\s]+/, '')
200
+ v[1] = v[1][0, v[1].index("\n\n")] if v[1].include?("\n\n")
197
201
  v[1] << "\n" unless v[1].end_with?("\n")
198
202
  end
199
203
  return v
data/lib/sisimai/rhost.rb CHANGED
@@ -19,15 +19,11 @@ module Sisimai
19
19
  '.email.ua' => 'IUA',
20
20
  'lsean.ezweb.ne.jp' => 'KDDI',
21
21
  'msmx.au.com' => 'KDDI',
22
+ 'charter.net' => 'Spectrum',
23
+ 'cox.net' => 'Cox',
22
24
  '.qq.com' => 'TencentQQ',
23
25
  }.freeze
24
26
 
25
- # Retrun the list of remote hosts Sisimai support
26
- # @return [Array] Remote host list
27
- def list
28
- return RhostClass.keys
29
- end
30
-
31
27
  # The value of "rhost" is listed in RhostClass or not
32
28
  # @param [String] argvs Remote host name
33
29
  # @return [True,False] True: matched
@@ -49,9 +45,10 @@ module Sisimai
49
45
 
50
46
  # Detect the bounce reason from certain remote hosts
51
47
  # @param [Sisimai::Data] argvs Parsed email object
48
+ # @param [String] proxy The alternative of the "rhost"
52
49
  # @return [String] The value of bounce reason
53
- def get(argvs)
54
- remotehost = argvs.rhost.downcase
50
+ def get(argvs, proxy = nil)
51
+ remotehost = proxy || argvs.rhost.downcase
55
52
  rhostclass = ''
56
53
  modulename = ''
57
54
 
@@ -62,6 +59,7 @@ module Sisimai
62
59
  rhostclass = modulename.gsub('::', '/').downcase
63
60
  break
64
61
  end
62
+ return nil if rhostclass.empty?
65
63
 
66
64
  require rhostclass
67
65
  reasontext = Module.const_get(modulename).get(argvs)
@@ -0,0 +1,112 @@
1
+ module Sisimai
2
+ module Rhost
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
4
+ # object as an argument of get() method when the value of "destination" of
5
+ # the object is "charter.net". This class is called only Sisimai::Data class.
6
+ module Cox
7
+ class << self
8
+ # Imported from p5-Sisimail/lib/Sisimai/Rhost/Cox.pm
9
+ ErrorCodes = {
10
+ # https://www.cox.com/residential/support/email-error-codes.html
11
+ 'CXBL' => 'blocked', # The sending IP address has been blocked by Cox due to exhibiting spam-like behavior.
12
+ 'CXTHRT' => 'securityerror', # Email sending limited due to suspicious account activity.
13
+ 'CXMJ' => 'securityerror', # Email sending blocked due to suspicious account activity on primary Cox account.
14
+ 'CXDNS' => 'blocked', # There was an issue with the connecting IP address Domain Name System (DNS).
15
+ 'CXSNDR' => 'rejected', # There was a problem with the sender's domain.
16
+ 'CXSMTP' => 'rejected', # Your email wasn't delivered because Cox was unable to verify that it came from a legitimate email sender.
17
+ 'CXCNCT' => 'toomanyconn', # There is a limit to the number of concurrent SMTP connections per IP address
18
+ 'CXMXRT' => 'toomanyconn', # The email sender has exceeded the maximum number of sent email allowed.
19
+ 'CDRBL' => 'blocked', # The sending IP address has been temporarily blocked by Cox due to exhibiting spam-like behavior.
20
+ 'IPBL0001' => 'blocked', # The sending IP address is listed in the Spamhaus Zen DNSBL.
21
+ 'IPBL0010' => 'blocked', # The sending IP is listed in the Return Path DNSBL.
22
+ 'IPBL0100' => 'blocked', # The sending IP is listed in the Invaluement ivmSIP DNSBL.
23
+ 'IPBL0011' => 'blocked', # The sending IP is in the Spamhaus Zen and Return Path DNSBLs.
24
+ 'IPBL0101' => 'blocked', # The sending IP is in the Spamhaus Zen and Invaluement ivmSIP DNSBLs.
25
+ 'IPBL0110' => 'blocked', # The sending IP is in the Return Path and Invaluement ivmSIP DNSBLs.
26
+ 'IPBL0111' => 'blocked', # The sending IP is in the Spamhaus Zen, Return Path and Invaluement ivmSIP DNSBLs.
27
+ 'IPBL1000' => 'blocked', # The sending IP address is listed on a CSI blacklist. You can check your status on the CSI website.
28
+ 'IPBL1001' => 'blocked', # The sending IP is listed in the Cloudmark CSI and Spamhaus Zen DNSBLs.
29
+ 'IPBL1010' => 'blocked', # The sending IP is listed in the Cloudmark CSI and Return Path DNSBLs.
30
+ 'IPBL1011' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen and Return Path DNSBLs.
31
+ 'IPBL1100' => 'blocked', # The sending IP is listed in the Cloudmark CSI and Invaluement ivmSIP DNSBLs.
32
+ 'IPBL1101' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen and Invaluement IVMsip DNSBLs.
33
+ 'IPBL1110' => 'blocked', # The sending IP is in the Cloudmark CSI, Return Path and Invaluement ivmSIP DNSBLs.
34
+ 'IPBL1111' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen, Return Path and Invaluement ivmSIP DNSBLs.
35
+ 'IPBL00001' => 'blocked', # The sending IP address is listed on a Spamhaus blacklist. Check your status at Spamhaus.
36
+ 'URLBL011' => 'spamdetected', # A URL within the body of the message was found on blocklists SURBL and Spamhaus DBL.
37
+ 'URLBL101' => 'spamdetected', # A URL within the body of the message was found on blocklists SURBL and ivmURI.
38
+ 'URLBL110' => 'spamdetected', # A URL within the body of the message was found on blocklists Spamhaus DBL and ivmURI.
39
+ 'URLBL1001' => 'spamdetected', # The URL is listed on a Spamhaus blacklist. Check your status at Spamhaus.
40
+ }.freeze
41
+ MessagesOf = {
42
+ 'blocked' => [
43
+ # Cox requires that all connecting email servers contain valid reverse DNS PTR records.
44
+ 'rejected - no rDNS',
45
+ # An email client has repeatedly sent bad commands or invalid passwords resulting in a three-hour block of the client's IP address.
46
+ 'cox too many bad commands from',
47
+ # The reverse DNS check of the sending server IP address has failed.
48
+ 'DNS check failure - try again later',
49
+ # The sending IP address has exceeded the threshold of invalid recipients and has been blocked.
50
+ 'Too many invalid recipients',
51
+ ],
52
+ 'notaccept' => [
53
+ # Our systems are experiencing an issue which is causing a temporary inability to accept new email.
54
+ 'ESMTP server temporarily not available',
55
+ ],
56
+ 'policyviolation' => [
57
+ # The sending server has attempted to communicate too soon within the SMTP transaction
58
+ 'ESMTP no data before greeting',
59
+ # The message has been rejected because it contains an attachment with one of the following prohibited
60
+ # file types, which commonly contain viruses: .shb, .shs, .vbe, .vbs, .wsc, .wsf, .wsh, .pif, .msc,
61
+ # .msi, .msp, .reg, .sct, .bat, .chm, .isp, .cpl, .js, .jse, .scr, .exe.
62
+ 'attachment extension is forbidden',
63
+ ],
64
+ 'rejected' => [
65
+ # Cox requires that all sender domains resolve to a valid MX or A-record within DNS.
66
+ 'sender rejected',
67
+ ],
68
+ 'toomanyconn' => [
69
+ # The sending IP address has exceeded the five maximum concurrent connection limit.
70
+ 'too many sessions from',
71
+ # The SMTP connection has exceeded the 100 email message threshold and was disconnected.
72
+ 'requested action aborted: try again later',
73
+ # The sending IP address has exceeded one of these rate limits and has been temporarily blocked.
74
+ 'Message threshold exceeded',
75
+ ],
76
+ 'userunknown' => [
77
+ 'recipient rejected', # The intended recipient is not a valid Cox Email account.
78
+ ],
79
+ }.freeze
80
+
81
+ # Detect bounce reason from https://cox.com/
82
+ # @param [Sisimai::Data] argvs Parsed email object
83
+ # @return [String, Nil] The bounce reason at Cox
84
+ # @since v4.25.8
85
+ def get(argvs)
86
+ statusmesg = argvs.diagnosticcode
87
+ codenumber = 0
88
+
89
+ if cv = statusmesg.match(/AUP#([0-9A-Z]+)/)
90
+ # Capture the numeric part of the error code
91
+ codenumber = cv[1]
92
+ end
93
+ reasontext = ErrorCodes[codenumber] || ''
94
+
95
+ if reasontext.empty?
96
+ # The error code was not found in ErrorCodes
97
+ MessagesOf.each_key do |e|
98
+ # Try to find with each error message defined in MessagesOf
99
+ next unless MessagesOf[e].any? { |a| statusmesg.include?(a) }
100
+ reasontext = e
101
+ break
102
+ end
103
+ end
104
+
105
+ return reasontext
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+ end
112
+
@@ -22,6 +22,7 @@ module Sisimai
22
22
  '5.2.2' => [{ reason: 'mailboxfull', string: 'Mailbox full' }],
23
23
  '5.2.3' => [{ reason: 'exceedlimit', string: 'Message too large' }],
24
24
  '5.2.4' => [{ reason: 'systemerror', string: 'Mailing list expansion problem' }],
25
+ '5.2.14' => [{ reason: 'systemerror', string: 'misconfigured forwarding address' }],
25
26
  '5.2.122' => [{ reason: 'toomanyconn' ,string: 'The recipient has exceeded their limit for' }],
26
27
  '5.3.3' => [{ reason: 'systemfull', string: 'Unrecognized command' }],
27
28
  '5.3.4' => [{ reason: 'mesgtoobig', string: 'Message too big for system' }],
@@ -29,6 +30,7 @@ module Sisimai
29
30
  '5.4.1' => [{ reason: 'rejected', string: 'Recipient address rejected: Access denied' }],
30
31
  '5.4.11' => [{ reason: 'contenterror',string: 'Agent generated message depth exceeded' }],
31
32
  '5.4.14' => [{ reason: 'networkerror',string: 'Hop count exceeded' }],
33
+ '5.4.310' => [{ reason: 'systemerror', string: 'does not exist' }], # DNS domain * does not exist
32
34
  '5.5.2' => [{ reason: 'syntaxerror', string: 'Send hello first' }],
33
35
  '5.5.3' => [{ reason: 'syntaxerror', string: 'Too many recipients' }],
34
36
  '5.5.4' => [{ reason: 'filtered', string: 'Invalid domain name' }],
@@ -100,7 +102,12 @@ module Sisimai
100
102
  'networkerror' => ['SMTPSEND.DNS.MxLoopback'],
101
103
  'rejected' => ['RESOLVER.RST.NotAuthorized'],
102
104
  'securityerror' => ['RESOLVER.RST.AuthRequired'],
103
- 'systemerror' => ['RESOLVER.ADR.Ambiguous', 'RESOLVER.ADR.BadPrimary', 'RESOLVER.ADR.InvalidInSmtp'],
105
+ 'systemerror' => [
106
+ 'RESOLVER.ADR.Ambiguous',
107
+ 'RESOLVER.ADR.BadPrimary',
108
+ 'RESOLVER.ADR.InvalidInSmtp',
109
+ 'RESOLVER.FWD.NotFound',
110
+ ],
104
111
  'toomanyconn' => ['RESOLVER.ADR.RecipLimit', 'RESOLVER.ADR.RecipientLimit'],
105
112
  'userunknown' => [
106
113
  'RESOLVER.ADR.RecipNotFound',