sisimai 5.0.3 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codecovio.yml +3 -1
  3. data/.github/workflows/rake-test.yml +6 -2
  4. data/ChangeLog.md +34 -0
  5. data/README-JA.md +20 -17
  6. data/README.md +20 -17
  7. data/lib/sisimai/arf.rb +3 -3
  8. data/lib/sisimai/fact/json.rb +2 -2
  9. data/lib/sisimai/fact/yaml.rb +2 -2
  10. data/lib/sisimai/fact.rb +4 -19
  11. data/lib/sisimai/lhost/activehunter.rb +4 -3
  12. data/lib/sisimai/lhost/amavis.rb +4 -4
  13. data/lib/sisimai/lhost/amazonses.rb +6 -6
  14. data/lib/sisimai/lhost/amazonworkmail.rb +4 -4
  15. data/lib/sisimai/lhost/aol.rb +4 -4
  16. data/lib/sisimai/lhost/apachejames.rb +4 -4
  17. data/lib/sisimai/lhost/barracuda.rb +4 -4
  18. data/lib/sisimai/lhost/bigfoot.rb +4 -4
  19. data/lib/sisimai/lhost/biglobe.rb +4 -4
  20. data/lib/sisimai/lhost/courier.rb +4 -4
  21. data/lib/sisimai/lhost/domino.rb +4 -4
  22. data/lib/sisimai/lhost/dragonfly.rb +114 -0
  23. data/lib/sisimai/lhost/einsundeins.rb +4 -4
  24. data/lib/sisimai/lhost/exchange2003.rb +4 -3
  25. data/lib/sisimai/lhost/exchange2007.rb +4 -3
  26. data/lib/sisimai/lhost/exim.rb +4 -4
  27. data/lib/sisimai/lhost/ezweb.rb +4 -4
  28. data/lib/sisimai/lhost/facebook.rb +4 -4
  29. data/lib/sisimai/lhost/fml.rb +4 -4
  30. data/lib/sisimai/lhost/gmail.rb +4 -4
  31. data/lib/sisimai/lhost/gmx.rb +4 -4
  32. data/lib/sisimai/lhost/googlegroups.rb +4 -4
  33. data/lib/sisimai/lhost/gsuite.rb +4 -4
  34. data/lib/sisimai/lhost/imailserver.rb +4 -3
  35. data/lib/sisimai/lhost/interscanmss.rb +5 -4
  36. data/lib/sisimai/lhost/kddi.rb +4 -4
  37. data/lib/sisimai/lhost/mailfoundry.rb +4 -4
  38. data/lib/sisimai/lhost/mailmarshalsmtp.rb +5 -4
  39. data/lib/sisimai/lhost/mailru.rb +4 -4
  40. data/lib/sisimai/lhost/mcafee.rb +4 -4
  41. data/lib/sisimai/lhost/messagelabs.rb +4 -3
  42. data/lib/sisimai/lhost/messagingserver.rb +5 -4
  43. data/lib/sisimai/lhost/mfilter.rb +4 -4
  44. data/lib/sisimai/lhost/mxlogic.rb +3 -3
  45. data/lib/sisimai/lhost/notes.rb +4 -4
  46. data/lib/sisimai/lhost/office365.rb +4 -4
  47. data/lib/sisimai/lhost/opensmtpd.rb +9 -7
  48. data/lib/sisimai/lhost/outlook.rb +4 -4
  49. data/lib/sisimai/lhost/postfix.rb +4 -4
  50. data/lib/sisimai/lhost/powermta.rb +4 -4
  51. data/lib/sisimai/lhost/qmail.rb +10 -10
  52. data/lib/sisimai/lhost/receivingses.rb +4 -4
  53. data/lib/sisimai/lhost/sendgrid.rb +4 -4
  54. data/lib/sisimai/lhost/sendmail.rb +4 -4
  55. data/lib/sisimai/lhost/surfcontrol.rb +4 -4
  56. data/lib/sisimai/lhost/v5sendmail.rb +5 -4
  57. data/lib/sisimai/lhost/verizon.rb +4 -4
  58. data/lib/sisimai/lhost/x1.rb +3 -3
  59. data/lib/sisimai/lhost/x2.rb +3 -3
  60. data/lib/sisimai/lhost/x3.rb +3 -3
  61. data/lib/sisimai/lhost/x4.rb +3 -3
  62. data/lib/sisimai/lhost/x5.rb +3 -3
  63. data/lib/sisimai/lhost/x6.rb +3 -3
  64. data/lib/sisimai/lhost/yahoo.rb +4 -4
  65. data/lib/sisimai/lhost/yandex.rb +4 -4
  66. data/lib/sisimai/lhost/zoho.rb +4 -4
  67. data/lib/sisimai/lhost.rb +5 -5
  68. data/lib/sisimai/mail/maildir.rb +1 -1
  69. data/lib/sisimai/mail/stdin.rb +1 -1
  70. data/lib/sisimai/mda.rb +3 -3
  71. data/lib/sisimai/message.rb +8 -8
  72. data/lib/sisimai/order.rb +1 -0
  73. data/lib/sisimai/reason/badreputation.rb +1 -1
  74. data/lib/sisimai/reason/norelaying.rb +1 -0
  75. data/lib/sisimai/reason/rejected.rb +1 -0
  76. data/lib/sisimai/reason.rb +8 -8
  77. data/lib/sisimai/rfc3464.rb +3 -3
  78. data/lib/sisimai/rfc3834.rb +2 -2
  79. data/lib/sisimai/rhost/apple.rb +92 -0
  80. data/lib/sisimai/rhost/cox.rb +81 -32
  81. data/lib/sisimai/rhost/franceptt.rb +84 -81
  82. data/lib/sisimai/rhost/godaddy.rb +205 -43
  83. data/lib/sisimai/rhost/google.rb +3 -5
  84. data/lib/sisimai/rhost/iua.rb +2 -2
  85. data/lib/sisimai/rhost/kddi.rb +6 -5
  86. data/lib/sisimai/rhost/microsoft.rb +4 -5
  87. data/lib/sisimai/rhost/mimecast.rb +15 -4
  88. data/lib/sisimai/rhost/nttdocomo.rb +1 -1
  89. data/lib/sisimai/rhost/spectrum.rb +100 -40
  90. data/lib/sisimai/rhost/tencent.rb +46 -25
  91. data/lib/sisimai/rhost/yahooinc.rb +110 -0
  92. data/lib/sisimai/rhost.rb +28 -35
  93. data/lib/sisimai/smtp/reply.rb +4 -3
  94. data/lib/sisimai/smtp/transcript.rb +3 -3
  95. data/lib/sisimai/version.rb +1 -1
  96. data/lib/sisimai.rb +0 -6
  97. data/set-of-emails/maildir/bsd/lhost-dragonfly-01.eml +36 -0
  98. data/set-of-emails/maildir/bsd/lhost-dragonfly-02.eml +32 -0
  99. data/set-of-emails/maildir/bsd/lhost-dragonfly-03.eml +32 -0
  100. data/set-of-emails/maildir/bsd/lhost-dragonfly-04.eml +31 -0
  101. data/set-of-emails/maildir/bsd/lhost-dragonfly-05.eml +32 -0
  102. data/set-of-emails/maildir/bsd/lhost-dragonfly-06.eml +32 -0
  103. data/set-of-emails/maildir/bsd/lhost-dragonfly-07.eml +32 -0
  104. data/set-of-emails/maildir/bsd/lhost-dragonfly-08.eml +32 -0
  105. data/set-of-emails/maildir/bsd/lhost-dragonfly-09.eml +32 -0
  106. data/set-of-emails/maildir/bsd/lhost-dragonfly-10.eml +32 -0
  107. data/set-of-emails/maildir/bsd/lhost-dragonfly-11.eml +32 -0
  108. data/set-of-emails/maildir/bsd/lhost-dragonfly-12.eml +32 -0
  109. data/set-of-emails/maildir/bsd/lhost-dragonfly-13.eml +32 -0
  110. data/set-of-emails/maildir/bsd/lhost-dragonfly-14.eml +32 -0
  111. data/set-of-emails/maildir/bsd/lhost-dragonfly-15.eml +32 -0
  112. data/set-of-emails/maildir/bsd/lhost-dragonfly-16.eml +32 -0
  113. data/set-of-emails/maildir/bsd/lhost-dragonfly-17.eml +32 -0
  114. data/set-of-emails/maildir/bsd/lhost-dragonfly-18.eml +32 -0
  115. data/set-of-emails/maildir/bsd/lhost-dragonfly-19.eml +32 -0
  116. data/set-of-emails/maildir/bsd/lhost-dragonfly-20.eml +32 -0
  117. data/set-of-emails/maildir/bsd/lhost-dragonfly-21.eml +33 -0
  118. data/set-of-emails/maildir/bsd/lhost-dragonfly-22.eml +32 -0
  119. data/set-of-emails/maildir/bsd/lhost-dragonfly-23.eml +32 -0
  120. data/set-of-emails/maildir/bsd/lhost-dragonfly-24.eml +32 -0
  121. data/set-of-emails/maildir/bsd/lhost-dragonfly-25.eml +33 -0
  122. data/set-of-emails/maildir/bsd/lhost-dragonfly-26.eml +33 -0
  123. data/set-of-emails/maildir/bsd/lhost-dragonfly-27.eml +47 -0
  124. data/set-of-emails/maildir/bsd/lhost-dragonfly-28.eml +47 -0
  125. data/set-of-emails/maildir/bsd/lhost-dragonfly-29.eml +32 -0
  126. data/set-of-emails/maildir/bsd/lhost-dragonfly-30.eml +32 -0
  127. data/set-of-emails/maildir/bsd/lhost-opensmtpd-10.eml +58 -0
  128. data/set-of-emails/maildir/bsd/lhost-opensmtpd-11.eml +58 -0
  129. data/set-of-emails/maildir/bsd/lhost-opensmtpd-12.eml +62 -0
  130. data/set-of-emails/maildir/bsd/lhost-opensmtpd-13.eml +62 -0
  131. data/set-of-emails/maildir/bsd/lhost-opensmtpd-14.eml +58 -0
  132. data/set-of-emails/maildir/bsd/lhost-opensmtpd-15.eml +63 -0
  133. data/set-of-emails/maildir/bsd/lhost-opensmtpd-16.eml +62 -0
  134. data/set-of-emails/maildir/bsd/lhost-opensmtpd-17.eml +63 -0
  135. data/set-of-emails/maildir/bsd/lhost-qmail-11.eml +29 -0
  136. data/set-of-emails/maildir/bsd/lhost-qmail-12.eml +29 -0
  137. data/set-of-emails/maildir/bsd/lhost-qmail-13.eml +29 -0
  138. data/set-of-emails/maildir/bsd/lhost-qmail-14.eml +34 -0
  139. data/set-of-emails/maildir/bsd/lhost-qmail-15.eml +30 -0
  140. data/set-of-emails/maildir/bsd/lhost-qmail-16.eml +31 -0
  141. data/set-of-emails/maildir/bsd/lhost-qmail-17.eml +38 -0
  142. data/set-of-emails/maildir/bsd/lhost-qmail-18.eml +31 -0
  143. data/set-of-emails/maildir/bsd/lhost-qmail-19.eml +31 -0
  144. data/set-of-emails/maildir/bsd/lhost-qmail-20.eml +46 -0
  145. data/set-of-emails/maildir/bsd/lhost-qmail-21.eml +41 -0
  146. data/set-of-emails/maildir/bsd/lhost-qmail-22.eml +42 -0
  147. data/set-of-emails/maildir/bsd/lhost-qmail-23.eml +43 -0
  148. data/set-of-emails/maildir/bsd/lhost-qmail-24.eml +43 -0
  149. data/set-of-emails/maildir/bsd/lhost-qmail-25.eml +54 -0
  150. data/set-of-emails/maildir/bsd/rhost-apple-01.eml +79 -0
  151. data/set-of-emails/maildir/bsd/rhost-apple-02.eml +81 -0
  152. data/set-of-emails/maildir/bsd/rhost-apple-03.eml +75 -0
  153. data/set-of-emails/maildir/bsd/rhost-apple-04.eml +74 -0
  154. data/set-of-emails/maildir/bsd/rhost-yahooinc-01.eml +80 -0
  155. data/set-of-emails/maildir/bsd/rhost-yahooinc-02.eml +83 -0
  156. data/set-of-emails/maildir/bsd/rhost-yahooinc-03.eml +125 -0
  157. metadata +65 -2
@@ -351,11 +351,11 @@ module Sisimai
351
351
  # @param options mail [String] from From line of mbox
352
352
  # @param options mail [Hash] header Email header data
353
353
  # @param options mail [String] rfc822 Original message part
354
- # @param options mail [Array] ds Delivery status list(parsed data)
354
+ # @param options mail [Array] ds Delivery status list(decoded data)
355
355
  # @param options argvs [String] body Email message body
356
356
  # @param options argvs [Array] tryonfirst MTA module list to load on first
357
357
  # @param options argvs [Array] tobeloaded User defined MTA module list
358
- # @return [Hash] Parsed and structured bounce mails
358
+ # @return [Hash] Decoded and structured bounce mails
359
359
  def sift(argvs)
360
360
  return nil unless argvs['mail']
361
361
  return nil unless argvs['body']
@@ -414,7 +414,7 @@ module Sisimai
414
414
  end
415
415
  end
416
416
 
417
- catch :PARSER do
417
+ catch :DECODER do
418
418
  while true
419
419
  # 1. User-Defined Module
420
420
  # 2. MTA Module Candidates to be tried on first
@@ -428,7 +428,7 @@ module Sisimai
428
428
  havesifted = Module.const_get(r).inquire(mailheader, bodystring)
429
429
  haveloaded[r] = true
430
430
  modulename = r
431
- throw :PARSER if havesifted
431
+ throw :DECODER if havesifted
432
432
  end
433
433
 
434
434
  [argvs['tryonfirst'], DefaultSet].flatten.each do |r|
@@ -438,7 +438,7 @@ module Sisimai
438
438
  havesifted = Module.const_get(r).inquire(mailheader, bodystring)
439
439
  haveloaded[r] = true
440
440
  modulename = r
441
- throw :PARSER if havesifted
441
+ throw :DECODER if havesifted
442
442
  end
443
443
 
444
444
  unless haveloaded['Sisimai::RFC3464']
@@ -446,14 +446,14 @@ module Sisimai
446
446
  require 'sisimai/rfc3464'
447
447
  havesifted = Sisimai::RFC3464.inquire(mailheader, bodystring)
448
448
  modulename = 'RFC3464'
449
- throw :PARSER if havesifted
449
+ throw :DECODER if havesifted
450
450
  end
451
451
 
452
452
  unless haveloaded['Sisimai::ARF']
453
453
  # Feedback Loop message
454
454
  require 'sisimai/arf'
455
455
  havesifted = Sisimai::ARF.inquire(mailheader, bodystring)
456
- throw :PARSER if havesifted
456
+ throw :DECODER if havesifted
457
457
  end
458
458
 
459
459
  unless haveloaded['Sisimai::RFC3834']
@@ -461,7 +461,7 @@ module Sisimai
461
461
  require 'sisimai/rfc3834'
462
462
  havesifted = Sisimai::RFC3834.inquire(mailheader, bodystring)
463
463
  modulename = 'RFC3834'
464
- throw :PARSER if havesifted
464
+ throw :DECODER if havesifted
465
465
  end
466
466
 
467
467
  break # as of now, we have no sample email for coding this block
data/lib/sisimai/order.rb CHANGED
@@ -105,6 +105,7 @@ module Sisimai
105
105
  'loop-alert' => ['Sisimai::Lhost::FML'],
106
106
  'mail-delivery' => [
107
107
  'Sisimai::Lhost::Exim',
108
+ 'Sisimai::Lhost::DragonFly',
108
109
  'Sisimai::Lhost::MailRu',
109
110
  'Sisimai::Lhost::GMX',
110
111
  'Sisimai::Lhost::EinsUndEins',
@@ -19,6 +19,7 @@ module Sisimai
19
19
  'has been temporarily rate limited due to ip reputation',
20
20
  'ip/domain reputation problems',
21
21
  'likely suspicious due to the very low reputation',
22
+ 'temporarily deferred due to unexpected volume or user complaints', # Yahoo Inc.
22
23
  "the sending mta's poor reputation",
23
24
  ].freeze
24
25
  def text; return 'badreputation'; end
@@ -40,7 +41,6 @@ module Sisimai
40
41
  # false: is not BadReputation
41
42
  # @see http://www.ietf.org/rfc/rfc2822.txt
42
43
  def true(argvs)
43
- return nil if argvs['deliverystatus'].empty?
44
44
  return true if argvs['reason'] == 'badreputation'
45
45
  return true if match(argvs['diagnosticcode'].downcase)
46
46
  return false
@@ -15,6 +15,7 @@ module Sisimai
15
15
  'insecure mail relay',
16
16
  'is not permitted to relay through this server without authentication',
17
17
  'mail server requires authentication when attempting to send to a non-local e-mail address', # MailEnable
18
+ 'no relaying',
18
19
  'not a gateway',
19
20
  'not allowed to relay through this machine',
20
21
  'not an open relay, so get lost',
@@ -63,6 +63,7 @@ module Sisimai
63
63
  'sender rejected',
64
64
  'sender domain is empty',
65
65
  'sender verify failed', # Exim callout
66
+ 'sender was rejected', # qmail
66
67
  'spam reporting address', # SendGrid|a message to an address has previously been marked as Spam by the recipient.
67
68
  'syntax error: empty email address',
68
69
  'the message has been rejected by batv defense',
@@ -38,13 +38,13 @@ module Sisimai
38
38
  ClassOrder = [
39
39
  %w[
40
40
  MailboxFull MesgTooBig ExceedLimit Suspend HasMoved NoRelaying AuthFailure UserUnknown
41
- Filtered RequirePTR NotCompliantRFC Rejected HostUnknown SpamDetected Speeding TooManyConn
42
- Blocked
41
+ Filtered RequirePTR NotCompliantRFC BadReputation Rejected HostUnknown SpamDetected Speeding
42
+ TooManyConn Blocked
43
43
  ],
44
44
  %w[
45
- MailboxFull SpamDetected PolicyViolation VirusDetected NoRelaying AuthFailure
46
- BadReputation SecurityError SystemError NetworkError Speeding Suspend Expired ContentError
47
- SystemFull NotAccept MailerError
45
+ MailboxFull AuthFailure BadReputation Speeding SpamDetected VirusDetected PolicyViolation
46
+ NoRelaying SystemError NetworkError Suspend ContentError SystemFull NotAccept Expired
47
+ SecurityError MailerError
48
48
  ],
49
49
  %w[
50
50
  MailboxFull MesgTooBig ExceedLimit Suspend UserUnknown Filtered Rejected HostUnknown
@@ -55,7 +55,7 @@ module Sisimai
55
55
  ]
56
56
 
57
57
  # Detect the bounce reason
58
- # @param [Hash] argvs Parsed email object
58
+ # @param [Hash] argvs Decoded email object
59
59
  # @return [String, nil] Bounce reason or nil if the argument is missing or not Hash
60
60
  # @see anotherone
61
61
  def get(argvs)
@@ -112,7 +112,7 @@ module Sisimai
112
112
  end
113
113
 
114
114
  # Detect the other bounce reason, fall back method for get()
115
- # @param [Hash] argvs Parsed email object
115
+ # @param [Hash] argvs Decoded email object
116
116
  # @return [String, Nil] Bounce reason or nli if the argument is missing or not Hash
117
117
  # @see get
118
118
  def anotherone(argvs)
@@ -216,7 +216,7 @@ module Sisimai
216
216
  end
217
217
  return reasontext unless reasontext.empty?
218
218
 
219
- if issuedcode.upcase == 'X-UNIX'
219
+ if issuedcode.upcase.include?('X-UNIX; ')
220
220
  # X-Unix; ...
221
221
  reasontext = 'mailererror'
222
222
  else
@@ -1,5 +1,5 @@
1
1
  module Sisimai
2
- # Sisimai::RFC3464 - bounce mail parser class for Fallback.
2
+ # Sisimai::RFC3464 - bounce mail decoder class for Fallback.
3
3
  module RFC3464
4
4
  class << self
5
5
  require 'sisimai/lhost'
@@ -96,7 +96,7 @@ module Sisimai
96
96
  # @param [Hash] mhead Message headers of a bounce email
97
97
  # @param [String] mbody Message body of a bounce email
98
98
  # @return [Hash] Bounce data list and message/rfc822 part
99
- # @return [Nil] it failed to parse or the arguments are missing
99
+ # @return [Nil] it failed to decode or the arguments are missing
100
100
  def inquire(mhead, mbody)
101
101
  fieldtable = Sisimai::RFC1894.FIELDTABLE
102
102
  permessage = {} # (Hash) Store values of each Per-Message field
@@ -233,7 +233,7 @@ module Sisimai
233
233
 
234
234
  # -----------------------------------------------------------------------------------------
235
235
  while true
236
- # Fallback, parse entire message body
236
+ # Fallback, decode the entire message body
237
237
  break if recipients > 0
238
238
 
239
239
  # Failed to get a recipient address at code above
@@ -33,7 +33,7 @@ module Sisimai
33
33
  # @param [Hash] mhead Message headers of a bounce email
34
34
  # @param [String] mbody Message body of a bounce email
35
35
  # @return [Hash] Bounce data list and message/rfc822 part
36
- # @return [Nil] it failed to parse or the arguments are missing
36
+ # @return [Nil] it failed to decode or the arguments are missing
37
37
  def inquire(mhead, mbody)
38
38
  leave = 0
39
39
  match = 0
@@ -98,7 +98,7 @@ module Sisimai
98
98
  MarkingsOf[:boundary] = q unless q.empty?
99
99
  end
100
100
 
101
- # BODY_PARSER: Get vacation message
101
+ # MESSAGE_BODY: Get the vacation message
102
102
  while e = bodyslices.shift do
103
103
  # Read the first 5 lines except a blank line
104
104
  countuntil += 1 if e.include?(MarkingsOf[:boundary])
@@ -0,0 +1,92 @@
1
+ module Sisimai
2
+ module Rhost
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
+ # of get() method when the value of "destination" of the object is "mail.icloud.com" or "apple.com".
5
+ # This class is called only Sisimai::Fact class.
6
+ module Apple
7
+ class << self
8
+ MessagesOf = {
9
+ 'authfailure' => [
10
+ # - 554 5.7.1 Your message was rejected due to example.jp's DMARC policy.
11
+ # See https://support.apple.com/en-us/HT204137 for
12
+ # - 554 5.7.1 [HME1] This message was blocked for failing both SPF and DKIM authentication
13
+ # checks. See https://support.apple.com/en-us/HT204137 for mailing best practices
14
+ 's dmarc policy',
15
+ 'blocked for failing both spf and dkim autentication checks',
16
+ ],
17
+ 'blocked' => [
18
+ # - 550 5.7.0 Blocked - see https://support.proofpoint.com/dnsbl-lookup.cgi?ip=192.0.1.2
19
+ # - 550 5.7.1 Your email was rejected due to having a domain present in the Spamhaus
20
+ # DBL -- see https://www.spamhaus.org/dbl/
21
+ # - 550 5.7.1 Mail from IP 192.0.2.1 was rejected due to listing in Spamhaus SBL.
22
+ # For details please see http://www.spamhaus.org/query/bl?ip=x.x.x.x
23
+ # - 554 ****-smtpin001.me.com ESMTP not accepting connections
24
+ 'rejected due to having a domain present in the spamhaus',
25
+ 'rejected due to listing in spamhaus',
26
+ 'blocked - see https://support.proofpoint.com/dnsbl-lookup',
27
+ 'not accepting connections',
28
+ ],
29
+ 'hasmoved' => [
30
+ # - 550 5.1.6 recipient no longer on server: *****@icloud.com
31
+ 'recipient no longer on server',
32
+ ],
33
+ 'mailboxfull' => [
34
+ # - 552 5.2.2 <****@icloud.com>: user is over quota (in reply to RCPT TO command)
35
+ 'user is over quota',
36
+ ],
37
+ 'norelaying' => [
38
+ # - 554 5.7.1 <*****@icloud.com>: Relay access denied
39
+ 'relay access denied',
40
+ ],
41
+ 'notaccept' => ['host/domain does not accept mail'],
42
+ 'policyviolation' => [
43
+ # - 550 5.7.1 [CS01] Message rejected due to local policy.
44
+ # Please visit https://support.apple.com/en-us/HT204137
45
+ 'due to local policy',
46
+ ],
47
+ 'rejected' => [
48
+ # - 450 4.1.8 <kijitora@example.jp>: Sender address rejected: Domain not found
49
+ 'sender address rejected',
50
+ ],
51
+ 'speeding' => [
52
+ # - 421 4.7.1 Messages to ****@icloud.com deferred due to excessive volume.
53
+ # Try again later - https://support.apple.com/en-us/HT204137
54
+ 'due to excessive volume',
55
+ ],
56
+ 'userunknown' => [
57
+ # - 550 5.1.1 <****@icloud.com>: inactive email address (in reply to RCPT TO command)
58
+ # - 550 5.1.1 unknown or illegal alias: ****@icloud.com
59
+ 'inactive email address',
60
+ 'user does not exist',
61
+ 'unknown or illegal alias',
62
+ ],
63
+ }.freeze
64
+
65
+ # Detect bounce reason from Apple iCloud Mail
66
+ # @param [Sisimai::Fact] argvs Decoded email object
67
+ # @return [String] The bounce reason for Apple
68
+ # @see https://support.apple.com/en-us/102322
69
+ # https://www.postmastery.com/icloud-postmastery-page/
70
+ # https://smtpfieldmanual.com/provider/apple
71
+ # @since v5.1.0
72
+ def get(argvs)
73
+ issuedcode = argvs['diagnosticcode'].downcase
74
+ reasontext = ''
75
+
76
+ MessagesOf.each_key do |e|
77
+ MessagesOf[e].each do |f|
78
+ next unless issuedcode.include?(f)
79
+ reasontext = e
80
+ break
81
+ end
82
+ break if reasontext.size > 0
83
+ end
84
+
85
+ return reasontext
86
+ end
87
+
88
+ end
89
+ end
90
+ end
91
+ end
92
+
@@ -6,16 +6,54 @@ module Sisimai
6
6
  module Cox
7
7
  class << self
8
8
  ErrorCodes = {
9
- # https://www.cox.com/residential/support/email-error-codes.html
10
- 'CXBL' => 'blocked', # The sending IP address has been blocked by Cox due to exhibiting spam-like behavior.
9
+ # CXBL
10
+ # - The sending IP address has been blocked by Cox due to exhibiting spam-like behavior.
11
+ # - Send an email request to Cox to ask for a sending IP address be unblocked.
12
+ # Note: Cox has sole discretion whether to unblock the sending IP address.
13
+ 'CXBL' => 'blocked',
14
+
15
+ # CXDNS
16
+ # - There was an issue with the connecting IP address Domain Name System (DNS).
17
+ # - The Reverse DNS (rDNS) lookup for your IP address is failing.
18
+ # - Confirm the IP address that sends your email.
19
+ # - Check the rDNS of that IP address. If it passes, then wait 24 hours and try resending
20
+ # your email.
21
+ 'CXDNS' => 'requireptr',
22
+
23
+ # CXSNDR
24
+ # - There was a problem with the sender's domain.
25
+ # - Your email failed authentication checks against your sending domain's SPF, DomainKeys,
26
+ # or DKIM policy.
27
+ 'CXSNDR' => 'authfailure',
28
+
29
+ # CXSMTP
30
+ # - There was a violation of SMTP protocol.
31
+ # - Your email wasn't delivered because Cox was unable to verify that it came from a
32
+ # legitimate email sender.
33
+ 'CXSMTP' => 'rejected',
34
+
35
+ # CXCNCT
36
+ # - There was a connection issue from the IP address.
37
+ # - There is a limit to the number of concurrent SMTP connections per IP address to
38
+ # protect the systems against attack. Ensure that the sending email server is not
39
+ # opening more than 10 concurrent connections to avoid reaching this limit.
40
+ 'CXCNCT' => 'toomanyconn',
41
+
42
+ # CXMXRT
43
+ # - The sender has sent email to too many recipients and needs to wait before sending
44
+ # more email.
45
+ # - The email sender has exceeded the maximum number of sent email allowed.
46
+ 'CXMXRT' => 'toomanyconn',
47
+
48
+ # CDRBL
49
+ # - The sending IP address has been temporarily blocked by Cox due to exhibiting spam-like
50
+ # behavior.
51
+ # - The block duration varies depending on reputation and other factors, but will not exceed
52
+ # 24 hours. Inspect email traffic for potential spam, and retry email delivery.
53
+ 'CDRBL' => 'blocked',
54
+
11
55
  'CXTHRT' => 'securityerror', # Email sending limited due to suspicious account activity.
12
56
  'CXMJ' => 'securityerror', # Email sending blocked due to suspicious account activity on primary Cox account.
13
- 'CXDNS' => 'blocked', # There was an issue with the connecting IP address Domain Name System (DNS).
14
- 'CXSNDR' => 'rejected', # There was a problem with the sender's domain.
15
- 'CXSMTP' => 'rejected', # Your email wasn't delivered because Cox was unable to verify that it came from a legitimate email sender.
16
- 'CXCNCT' => 'toomanyconn', # There is a limit to the number of concurrent SMTP connections per IP address
17
- 'CXMXRT' => 'toomanyconn', # The email sender has exceeded the maximum number of sent email allowed.
18
- 'CDRBL' => 'blocked', # The sending IP address has been temporarily blocked by Cox due to exhibiting spam-like behavior.
19
57
  'IPBL0001' => 'blocked', # The sending IP address is listed in the Spamhaus Zen DNSBL.
20
58
  'IPBL0010' => 'blocked', # The sending IP is listed in the Return Path DNSBL.
21
59
  'IPBL0100' => 'blocked', # The sending IP is listed in the Invaluement ivmSIP DNSBL.
@@ -32,6 +70,7 @@ module Sisimai
32
70
  'IPBL1110' => 'blocked', # The sending IP is in the Cloudmark CSI, Return Path and Invaluement ivmSIP DNSBLs.
33
71
  'IPBL1111' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen, Return Path and Invaluement ivmSIP DNSBLs.
34
72
  'IPBL00001' => 'blocked', # The sending IP address is listed on a Spamhaus blacklist. Check your status at Spamhaus.
73
+
35
74
  'URLBL011' => 'spamdetected', # A URL within the body of the message was found on blocklists SURBL and Spamhaus DBL.
36
75
  'URLBL101' => 'spamdetected', # A URL within the body of the message was found on blocklists SURBL and ivmURI.
37
76
  'URLBL110' => 'spamdetected', # A URL within the body of the message was found on blocklists Spamhaus DBL and ivmURI.
@@ -39,63 +78,73 @@ module Sisimai
39
78
  }.freeze
40
79
  MessagesOf = {
41
80
  'blocked' => [
42
- # Cox requires that all connecting email servers contain valid reverse DNS PTR records.
43
- 'rejected - no rDNS',
44
- # An email client has repeatedly sent bad commands or invalid passwords resulting in a three-hour block of the client's IP address.
81
+ # - An email client has repeatedly sent bad commands or invalid passwords resulting in
82
+ # a three-hour block of the client's IP address.
83
+ # - The sending IP address has exceeded the threshold of invalid recipients and has
84
+ # been blocked.
45
85
  'cox too many bad commands from',
46
- # The reverse DNS check of the sending server IP address has failed.
47
- 'DNS check failure - try again later',
48
- # The sending IP address has exceeded the threshold of invalid recipients and has been blocked.
49
- 'Too many invalid recipients',
86
+ 'too many invalid recipients',
50
87
  ],
51
- 'notaccept' => [
52
- # Our systems are experiencing an issue which is causing a temporary inability to accept new email.
53
- 'ESMTP server temporarily not available',
88
+ 'requireptr' => [
89
+ # - The reverse DNS check of the sending server IP address has failed.
90
+ # - Cox requires that all connecting email servers contain valid reverse DNS PTR records.
91
+ 'dns check failure - try again later',
92
+ 'rejected - no rdns',
54
93
  ],
55
94
  'policyviolation' => [
56
- # The sending server has attempted to communicate too soon within the SMTP transaction
57
- 'ESMTP no data before greeting',
58
- # The message has been rejected because it contains an attachment with one of the following prohibited
59
- # file types, which commonly contain viruses: .shb, .shs, .vbe, .vbs, .wsc, .wsf, .wsh, .pif, .msc,
60
- # .msi, .msp, .reg, .sct, .bat, .chm, .isp, .cpl, .js, .jse, .scr, .exe.
95
+ # - The sending server has attempted to communicate too soon within the SMTP transaction
96
+ # - The message has been rejected because it contains an attachment with one of the
97
+ # following prohibited file types, which commonly contain viruses: .shb, .shs, .vbe,
98
+ # .vbs, .wsc, .wsf, .wsh, .pif, .msc, .msi, .msp, .reg, .sct, .bat, .chm, .isp, .cpl,
99
+ # .js, .jse, .scr, .exe.
100
+ 'esmtp no data before greeting',
61
101
  'attachment extension is forbidden',
62
102
  ],
63
103
  'rejected' => [
64
104
  # Cox requires that all sender domains resolve to a valid MX or A-record within DNS.
65
105
  'sender rejected',
66
106
  ],
107
+ 'systemerror' => [
108
+ # - Our systems are experiencing an issue which is causing a temporary inability to
109
+ # accept new email.
110
+ 'esmtp server temporarily not available',
111
+ ],
67
112
  'toomanyconn' => [
68
- # The sending IP address has exceeded the five maximum concurrent connection limit.
113
+ # - The sending IP address has exceeded the five maximum concurrent connection limit.
114
+ # - The SMTP connection has exceeded the 100 email message threshold and was disconnected.
115
+ # - The sending IP address has exceeded one of these rate limits and has been temporarily
116
+ # blocked.
69
117
  'too many sessions from',
70
- # The SMTP connection has exceeded the 100 email message threshold and was disconnected.
71
118
  'requested action aborted: try again later',
72
- # The sending IP address has exceeded one of these rate limits and has been temporarily blocked.
73
- 'Message threshold exceeded',
119
+ 'message threshold exceeded',
74
120
  ],
75
121
  'userunknown' => [
76
- 'recipient rejected', # The intended recipient is not a valid Cox Email account.
122
+ # - The intended recipient is not a valid Cox Email account.
123
+ 'recipient rejected',
77
124
  ],
78
125
  }.freeze
79
126
 
80
127
  # Detect bounce reason from https://cox.com/
81
- # @param [Sisimai::Fact] argvs Parsed email object
128
+ # @param [Sisimai::Fact] argvs Decoded email object
82
129
  # @return [String, Nil] The bounce reason at Cox
130
+ # @see https://www.cox.com/residential/support/email-error-codes.html
83
131
  # @since v4.25.8
84
132
  def get(argvs)
85
- statusmesg = argvs['diagnosticcode']
133
+ issuedcode = argvs['diagnosticcode']
86
134
  codenumber = 0
87
135
 
88
- if cv = statusmesg.match(/AUP#([0-9A-Z]+)/)
136
+ if cv = issuedcode.match(/AUP#([0-9A-Z]+)/)
89
137
  # Capture the numeric part of the error code
90
138
  codenumber = cv[1]
91
139
  end
92
140
  reasontext = ErrorCodes[codenumber] || ''
93
141
 
142
+ issuedcode = argvs['diagnosticcode'].downcase
94
143
  if reasontext.empty?
95
144
  # The error code was not found in ErrorCodes
96
145
  MessagesOf.each_key do |e|
97
146
  # Try to find with each error message defined in MessagesOf
98
- next unless MessagesOf[e].any? { |a| statusmesg.include?(a) }
147
+ next unless MessagesOf[e].any? { |a| issuedcode.include?(a) }
99
148
  reasontext = e
100
149
  break
101
150
  end