sisimai 5.4.0-java → 5.5.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codecovio.yml +1 -1
  3. data/.github/workflows/rake-test.yml +1 -1
  4. data/ChangeLog.md +45 -0
  5. data/Makefile +2 -4
  6. data/README-JA.md +23 -20
  7. data/README.md +23 -20
  8. data/lib/sisimai/address.rb +92 -44
  9. data/lib/sisimai/arf.rb +7 -8
  10. data/lib/sisimai/datetime.rb +2 -2
  11. data/lib/sisimai/fact/json.rb +1 -2
  12. data/lib/sisimai/fact/yaml.rb +1 -2
  13. data/lib/sisimai/fact.rb +60 -35
  14. data/lib/sisimai/lda.rb +2 -2
  15. data/lib/sisimai/lhost/activehunter.rb +4 -5
  16. data/lib/sisimai/lhost/amazonses.rb +3 -4
  17. data/lib/sisimai/lhost/apachejames.rb +2 -2
  18. data/lib/sisimai/lhost/biglobe.rb +6 -6
  19. data/lib/sisimai/lhost/courier.rb +7 -7
  20. data/lib/sisimai/lhost/domino.rb +6 -6
  21. data/lib/sisimai/lhost/dragonfly.rb +5 -5
  22. data/lib/sisimai/lhost/einsundeins.rb +4 -4
  23. data/lib/sisimai/lhost/exchange2003.rb +7 -7
  24. data/lib/sisimai/lhost/exchange2007.rb +3 -3
  25. data/lib/sisimai/lhost/exim.rb +7 -7
  26. data/lib/sisimai/lhost/ezweb.rb +3 -2
  27. data/lib/sisimai/lhost/fml.rb +9 -9
  28. data/lib/sisimai/lhost/gmail.rb +9 -9
  29. data/lib/sisimai/lhost/gmx.rb +3 -3
  30. data/lib/sisimai/lhost/googlegroups.rb +6 -7
  31. data/lib/sisimai/lhost/googleworkspace.rb +5 -6
  32. data/lib/sisimai/lhost/imailserver.rb +4 -4
  33. data/lib/sisimai/lhost/kddi.rb +4 -4
  34. data/lib/sisimai/lhost/mailfoundry.rb +3 -3
  35. data/lib/sisimai/lhost/{mailmarshalsmtp.rb → mailmarshal.rb} +5 -5
  36. data/lib/sisimai/lhost/messagingserver.rb +8 -8
  37. data/lib/sisimai/lhost/mfilter.rb +8 -4
  38. data/lib/sisimai/lhost/mimecast.rb +105 -0
  39. data/lib/sisimai/lhost/notes.rb +5 -5
  40. data/lib/sisimai/lhost/opensmtpd.rb +5 -5
  41. data/lib/sisimai/lhost/postfix.rb +38 -32
  42. data/lib/sisimai/lhost/qmail.rb +6 -6
  43. data/lib/sisimai/lhost/sendmail.rb +13 -13
  44. data/lib/sisimai/lhost/{interscanmss.rb → trendmicro.rb} +8 -9
  45. data/lib/sisimai/lhost/v5sendmail.rb +7 -7
  46. data/lib/sisimai/lhost/verizon.rb +3 -3
  47. data/lib/sisimai/lhost/x1.rb +7 -4
  48. data/lib/sisimai/lhost/x2.rb +40 -12
  49. data/lib/sisimai/lhost/x3.rb +3 -3
  50. data/lib/sisimai/lhost/x6.rb +2 -2
  51. data/lib/sisimai/lhost/zoho.rb +5 -5
  52. data/lib/sisimai/lhost.rb +18 -17
  53. data/lib/sisimai/mail/maildir.rb +4 -4
  54. data/lib/sisimai/mail/mbox.rb +4 -4
  55. data/lib/sisimai/mail/memory.rb +1 -1
  56. data/lib/sisimai/mail/stdin.rb +2 -2
  57. data/lib/sisimai/message.rb +34 -34
  58. data/lib/sisimai/order.rb +5 -4
  59. data/lib/sisimai/reason/authfailure.rb +1 -1
  60. data/lib/sisimai/reason/badreputation.rb +1 -1
  61. data/lib/sisimai/reason/blocked.rb +2 -1
  62. data/lib/sisimai/reason/contenterror.rb +1 -2
  63. data/lib/sisimai/reason/exceedlimit.rb +1 -1
  64. data/lib/sisimai/reason/expired.rb +1 -1
  65. data/lib/sisimai/reason/failedstarttls.rb +1 -1
  66. data/lib/sisimai/reason/filtered.rb +1 -1
  67. data/lib/sisimai/reason/hasmoved.rb +1 -1
  68. data/lib/sisimai/reason/hostunknown.rb +2 -2
  69. data/lib/sisimai/reason/mailboxfull.rb +1 -1
  70. data/lib/sisimai/reason/mailererror.rb +1 -1
  71. data/lib/sisimai/reason/mesgtoobig.rb +1 -1
  72. data/lib/sisimai/reason/networkerror.rb +1 -1
  73. data/lib/sisimai/reason/norelaying.rb +2 -2
  74. data/lib/sisimai/reason/notaccept.rb +2 -3
  75. data/lib/sisimai/reason/notcompliantrfc.rb +1 -1
  76. data/lib/sisimai/reason/policyviolation.rb +2 -4
  77. data/lib/sisimai/reason/rejected.rb +5 -3
  78. data/lib/sisimai/reason/requireptr.rb +1 -1
  79. data/lib/sisimai/reason/securityerror.rb +1 -1
  80. data/lib/sisimai/reason/spamdetected.rb +1 -1
  81. data/lib/sisimai/reason/speeding.rb +1 -1
  82. data/lib/sisimai/reason/suspend.rb +2 -1
  83. data/lib/sisimai/reason/systemerror.rb +1 -1
  84. data/lib/sisimai/reason/systemfull.rb +1 -1
  85. data/lib/sisimai/reason/toomanyconn.rb +1 -1
  86. data/lib/sisimai/reason/userunknown.rb +4 -3
  87. data/lib/sisimai/reason/vacation.rb +1 -1
  88. data/lib/sisimai/reason/virusdetected.rb +1 -1
  89. data/lib/sisimai/reason.rb +12 -12
  90. data/lib/sisimai/rfc1123.rb +58 -18
  91. data/lib/sisimai/rfc1894.rb +6 -8
  92. data/lib/sisimai/rfc2045.rb +25 -13
  93. data/lib/sisimai/rfc3464/thirdparty.rb +2 -3
  94. data/lib/sisimai/rfc3464.rb +6 -6
  95. data/lib/sisimai/rfc3834.rb +18 -8
  96. data/lib/sisimai/rfc5322.rb +9 -9
  97. data/lib/sisimai/rfc791.rb +2 -2
  98. data/lib/sisimai/rhost/aol.rb +4 -1
  99. data/lib/sisimai/rhost/apple.rb +11 -7
  100. data/lib/sisimai/rhost/cox.rb +9 -5
  101. data/lib/sisimai/rhost/facebook.rb +9 -3
  102. data/lib/sisimai/rhost/franceptt.rb +86 -37
  103. data/lib/sisimai/rhost/godaddy.rb +10 -1
  104. data/lib/sisimai/rhost/google.rb +26 -22
  105. data/lib/sisimai/rhost/gsuite.rb +1 -1
  106. data/lib/sisimai/rhost/kddi.rb +1 -1
  107. data/lib/sisimai/rhost/messagelabs.rb +160 -2
  108. data/lib/sisimai/rhost/microsoft.rb +80 -29
  109. data/lib/sisimai/rhost/mimecast.rb +30 -21
  110. data/lib/sisimai/rhost/nttdocomo.rb +69 -89
  111. data/lib/sisimai/rhost/outlook.rb +1 -1
  112. data/lib/sisimai/rhost/spectrum.rb +1 -1
  113. data/lib/sisimai/rhost/tencent.rb +5 -4
  114. data/lib/sisimai/rhost/yahooinc.rb +2 -2
  115. data/lib/sisimai/rhost/zoho.rb +72 -0
  116. data/lib/sisimai/rhost.rb +5 -4
  117. data/lib/sisimai/smtp/command.rb +2 -2
  118. data/lib/sisimai/smtp/reply.rb +11 -4
  119. data/lib/sisimai/smtp/status.rb +17 -8
  120. data/lib/sisimai/smtp/transcript.rb +3 -3
  121. data/lib/sisimai/string.rb +6 -10
  122. data/lib/sisimai/version.rb +1 -1
  123. data/lib/sisimai.rb +1 -1
  124. data/set-of-emails/maildir/bsd/lhost-exim-56.eml +40 -40
  125. data/set-of-emails/maildir/bsd/lhost-mfilter-05.eml +41 -0
  126. data/set-of-emails/maildir/bsd/lhost-mimecast-01.eml +46 -0
  127. data/set-of-emails/maildir/bsd/lhost-mimecast-02.eml +59 -0
  128. data/set-of-emails/maildir/bsd/lhost-postfix-79.eml +81 -0
  129. data/set-of-emails/maildir/bsd/lhost-postfix-80.eml +84 -0
  130. data/set-of-emails/maildir/bsd/lhost-x1-03.eml +26 -0
  131. data/set-of-emails/maildir/bsd/lhost-x1-04.eml +45 -0
  132. data/set-of-emails/maildir/bsd/lhost-x2-07.eml +30 -0
  133. data/set-of-emails/maildir/bsd/rfc3464-66.eml +170 -0
  134. data/set-of-emails/maildir/bsd/rfc3834-06.eml +59 -0
  135. data/set-of-emails/maildir/bsd/rhost-apple-05.eml +96 -0
  136. data/set-of-emails/maildir/bsd/rhost-zoho-01.eml +88 -0
  137. data/set-of-emails/maildir/bsd/rhost-zoho-02.eml +86 -0
  138. data/set-of-emails/maildir/bsd/rhost-zoho-03.eml +87 -0
  139. data/set-of-emails/maildir/bsd/rhost-zoho-04.eml +86 -0
  140. data/set-of-emails/maildir/not/rb-issue-368-bug.eml +39 -0
  141. data/sisimai-java.gemspec +1 -1
  142. data/sisimai.gemspec +1 -1
  143. metadata +27 -9
  144. /data/set-of-emails/maildir/bsd/{lhost-mailmarshalsmtp-02.eml → lhost-mailmarshal-02.eml} +0 -0
  145. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-01.eml → lhost-trendmicro-01.eml} +0 -0
  146. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-02.eml → lhost-trendmicro-02.eml} +0 -0
  147. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-03.eml → lhost-trendmicro-03.eml} +0 -0
@@ -205,9 +205,9 @@ module Sisimai
205
205
  # - A valid X.509 certificate that isn't expired must be presented. X.509 certificates
206
206
  # must be renewed after their expiration, commonly annually.
207
207
  ['5.7.51', 0, 0, 'restrictdomainstoipaddresses or restrictdomainstocertificate'],
208
- ['4.7.321', 0, 0, 'starttls-not-supported: destination mail server must support tls to receive mail'],
209
- ['5.7.321', 0, 0, 'starttls-not-supported: destination mail server must support tls to receive mail'],
210
- ['5.7.322', 0, 0, "certificate-expired: destination mail server's certificate is expired"],
208
+ ['4.7.321', 0, 0, 'starttls-not-supported:'],
209
+ ['5.7.321', 0, 0, 'starttls-not-supported:'],
210
+ ['5.7.322', 0, 0, "certificate-expired:"],
211
211
 
212
212
  # - Records are DNSSEC authentic, but one or multiple of these scenarios occurred:
213
213
  # - The destination mail server's certificate doesn't match with what is expected per
@@ -219,13 +219,13 @@ module Sisimai
219
219
  # validity of recipient address and determine if the destination server is configured
220
220
  # correctly to receive messages.
221
221
  # - For more information about DANE, see: https://datatracker.ietf.org/doc/html/rfc7671
222
- ['4.7.323', 0, 0, 'tlsa-invalid: The domain failed dane validation'],
223
- ['5.7.323', 0, 0, 'tlsa-invalid: The domain failed dane validation'],
222
+ ['4.7.323', 0, 0, 'tlsa-invalid:'],
223
+ ['5.7.323', 0, 0, 'tlsa-invalid:'],
224
224
 
225
225
  # - The destination domain indicated it was DNSSEC-authentic, but Exchange Online was
226
226
  # not able to verify it as DNSSEC-authentic.
227
- ['4.7.324', 0, 0, 'dnssec-invalid: destination domain returned invalid dnssec records'],
228
- ['5.7.324', 0, 0, 'dnssec-invalid: destination domain returned invalid dnssec records'],
227
+ ['4.7.324', 0, 0, 'dnssec-invalid:'],
228
+ ['5.7.324', 0, 0, 'dnssec-invalid:'],
229
229
 
230
230
  # - This happens when the presented certificate identities (CN and SAN) of a destina-
231
231
  # tion SMTP target host don't match any of the domains or MX host.
@@ -233,8 +233,8 @@ module Sisimai
233
233
  # validity of recipient address and determine if the destination server is configured
234
234
  # correctly to receive messages. For more information, see How SMTP DNS-based Authen-
235
235
  # tication of Named Entities (DANE) works to secure email communications.
236
- ['4.7.325', 0, 0, 'certificate-host-mismatch: remote certificate must have a common name or subject alternative name matching the hostname (dane)'],
237
- ['5.7.325', 0, 0, 'certificate-host-mismatch: remote certificate must have a common name or subject alternative name matching the hostname (dane)'],
236
+ ['4.7.325', 0, 0, 'certificate-host-mismatch:'],
237
+ ['5.7.325', 0, 0, 'certificate-host-mismatch:'],
238
238
  ],
239
239
  'mailboxfull' => [
240
240
  # Exchange Server 2019 ----------------------------------------------------------------
@@ -501,7 +501,7 @@ module Sisimai
501
501
  # - The sender has exceeded the recipient rate limit as described in Sending limits.
502
502
  # - This could indicate the account has been compromised and is being used to send
503
503
  # spam.
504
- ['5.1.90', 0, 0, "your message can't be sent because you've reached your daily limit for message recipients"],
504
+ ['5.1.90', 0, 0, "reached your daily limit for message recipients"],
505
505
 
506
506
  # - The sender has exceeded the recipient rate limit or the message rate limit as de-
507
507
  # scribed in Sending limits.
@@ -516,7 +516,7 @@ module Sisimai
516
516
  # Microsoft 365 or Office 365 users from rapidly filling their inboxes with a large
517
517
  # number of messages from errant automated notification systems or other single-send-
518
518
  # er mail storms.
519
- ['5.2.121', 0, 0, "recipient's per hour message receive limit from specific sender exceeded"],
519
+ ['5.2.121', 0, 0, "recipient's per hour message receive limit"],
520
520
 
521
521
  # - The Microsoft 365 or Office 365 recipient has exceeded the number of messages they
522
522
  # can receive per hour from all senders.
@@ -524,7 +524,7 @@ module Sisimai
524
524
  # messages they send per hour to a specific recipient. This limit helps protect
525
525
  # Microsoft 365 and Office 365 users from rapidly filling their inboxes with a large
526
526
  # number of messages from errant automated notification systems or other mail storms.
527
- ['5.2.122', 0, 0, "recipient's per hour message receive limit exceeded"],
527
+ ['5.2.122', 0, 0, "recipient's per hour message receive limit"],
528
528
 
529
529
  # - Access denied, [$SenderIPAddress] has exceeded permitted limits within $range range
530
530
  # - The sender's IPv6 range has attempted to send too many messages in too short a time
@@ -536,8 +536,8 @@ module Sisimai
536
536
  # - Ensure that any compromises or open relays have been resolved, and then contact
537
537
  # support through your regular channel. For more information, see Fix email delivery
538
538
  # issues for error codes 5.7.700 through 5.7.750 in Exchange Online.
539
- ['5.7.', 700, 749, 'access denied, tenant has exceeded threshold'],
540
- ['5.7.', 700, 749, 'access denied, traffic not accepted from this ip'],
539
+ ['5.7.', 700, 749, 'tenant has exceeded threshold'],
540
+ ['5.7.', 700, 749, 'traffic not accepted from this ip'],
541
541
  ],
542
542
  'suspend' => [
543
543
  # Exchange Online ---------------------------------------------------------------------
@@ -595,7 +595,7 @@ module Sisimai
595
595
  # is disabled. For this scenario to work, the organization's Office 365 administrator
596
596
  # should either enable Journaling Archive or change the journaling rule to journal
597
597
  # messages to a different location.
598
- ['5.3.190', 0, 0, 'journaling on-premises messages to microsoft 365 or office 365 not supported when journaling archive is disabled'],
598
+ ['5.3.190', 0, 0, 'when journaling archive is disabled'],
599
599
 
600
600
  # Previous versions of Exchange Server ------------------------------------------------
601
601
  ['5.0.0', 0, 0, 'helo / ehlo requires domain address'],
@@ -611,9 +611,9 @@ module Sisimai
611
611
  # Microsoft.Exchange.Transport.Net.Http.TransportHttpException(session Id: -1) ...(in reply to end of DATA command)
612
612
  # - 451 4.4.28 Message failed to be replicated:
613
613
  # System.Net.Http.HttpRequestException(session Id: ****) ... (in reply to end of DATA command)
614
- ["4.4.", "22", "28", "message failed to be replicated:"],
615
- ["4.4.3", "", "", "temporary server error. please try again later attr18"],
616
- ["4.7.0", "", "", "temporary server error. please try again later. prx4 nexthop:"],
614
+ ["4.4.", 22, 28, "message failed to be replicated:"],
615
+ ["4.4.3", 0, 0, "temporary server error. please try again later attr18"],
616
+ ["4.7.0", 0, 0, "temporary server error. please try again later. prx4 nexthop:"],
617
617
 
618
618
  # 550 5.4.318 Message expired, connection reset (SuspiciousRemoteServerError)
619
619
  # 450 4.4.318 Connection was closed abruptly (SuspiciousRemoteServerError)
@@ -728,6 +728,55 @@ module Sisimai
728
728
  ['5.1.2', 0, 0, 'invalid x.400 address'],
729
729
  ],
730
730
  }.freeze
731
+ ErrorCodes = {
732
+ # The mail server IP connecting to Outlook.com server has exceeded the rate limit allowed.
733
+ # Reason for rate limitation is related to IP/domain reputation.
734
+ "RP-001" => ["421", "badreputation"],
735
+
736
+ # The mail server IP connecting to Outlook.com server has exceeded the rate limit allowed
737
+ # on this connection. Reason for rate limitation is related to IP/domain reputation.
738
+ "RP-002" => ["421", "badreputation"],
739
+
740
+ # The mail server IP connecting to Outlook.com server has exceeded the connection limit
741
+ # allowed. Reason for limitation is related to IP/domain reputation.
742
+ "RP-003" => ["421", "badreputation"],
743
+
744
+ # Mail rejected by Outlook.com for policy reasons. Reasons for rejection may be related
745
+ # to content with spam-like characteristics or IP/domain reputation.
746
+ "SC-001" => ["550", "badreputation"],
747
+
748
+ # Mail rejected by Outlook.com for policy reasons. The mail server IP connecting to
749
+ # Outlook.com has exhibited namespace mining behavior.
750
+ "SC-002" => ["550", "policyviolation"],
751
+
752
+ # Mail rejected by Outlook.com for policy reasons. Your IP address appears to be an
753
+ # open proxy/relay.
754
+ "SC-003" => ["550", "blocked"],
755
+
756
+ # Mail rejected by Outlook.com for policy reasons. A block has been placed against your
757
+ # IP address because we have received complaints concerning mail coming from that IP
758
+ # address. We recommend enrolling in our Junk Email Reporting Program (JMRP), a free
759
+ # program intended to help senders remove unwanted recipients from their email list
760
+ "SC-004" => ["550", "blocked"],
761
+
762
+ # Mail rejected by Outlook.com for policy reasons. We generally do not accept email
763
+ # from dynamic IP's as they are not typically used to deliver unauthenticated SMTP email
764
+ # to an Internet mail server. (Spamhaus)
765
+ "DY-001" => ["550", "blocked"],
766
+
767
+ # Mail rejected by Outlook.com for policy reasons. The likely cause is a compromised or
768
+ # virus infected server/personal computer.
769
+ "DY-002" => ["550", "virusdetected"],
770
+
771
+ # Mail rejected by Outlook.com for policy reasons. If you are not an email/network admin
772
+ # please contact your Email/Internet Service Provider for help. For more information
773
+ # about this block and to request removal please go to: Spamhaus.
774
+ "OU-001" => ["550", "blocked"],
775
+
776
+ # Mail rejected by Outlook.com for policy reasons. Reasons for rejection may be related
777
+ # to content with spam-like characteristics or IP/domain reputation.
778
+ "OU-002" => ["550", "badreputation"],
779
+ }.freeze
731
780
 
732
781
  # Detect bounce reason from Exchange Server 2019 or older and Exchange Online
733
782
  # @param [Sisimai::Fact] argvs Decoded email object
@@ -735,12 +784,11 @@ module Sisimai
735
784
  # @since v4.17.2
736
785
  def find(argvs)
737
786
  return '' if argvs['deliverystatus'].empty?
738
- return '' unless Sisimai::SMTP::Status.test(argvs['deliverystatus'])
787
+ return '' if Sisimai::SMTP::Status.test(argvs['deliverystatus']) == false
739
788
 
740
789
  statuscode = argvs['deliverystatus']
741
790
  issuedcode = argvs['diagnosticcode'].downcase
742
791
  thirddigit = statuscode.split('.')[-1].to_i
743
- reasontext = ''
744
792
 
745
793
  MessagesOf.each_key do |e|
746
794
  # Each key is a reason name
@@ -748,22 +796,25 @@ module Sisimai
748
796
  # ["status-code", min, max, "error message"]
749
797
  if f[1] == f[2]
750
798
  # This error code have no range
751
- next unless statuscode == f[0]
799
+ next if statuscode != f[0]
752
800
  else
753
801
  # This error code has a range
754
- next unless statuscode.start_with?(f[0])
755
- next if thirddigit < f[1]
756
- next if thirddigit > f[2]
802
+ next if statuscode.start_with?(f[0]) == false
803
+ next if thirddigit < f[1] || thirddigit > f[2]
757
804
  end
758
805
 
759
- next unless issuedcode.include?(f[3])
760
- reasontext = e
761
- break
806
+ return e if issuedcode.include?(f[3])
762
807
  end
763
- break unless reasontext.empty?
764
808
  end
765
809
 
766
- return reasontext
810
+ ErrorCodes.each_key do |e|
811
+ # The key name is an error code described at Outlook.com Postmaster/Troubleshooting
812
+ # https://substrate.office.com/ip-domain-management-snds/postmaster/troubleshooting
813
+ next if argvs['diagnosticcode'].include?(e) == false
814
+ return ErrorCodes[e][1] if argvs['replycode'] == ErrorCodes[e][0]
815
+ end
816
+
817
+ return ""
767
818
  end
768
819
 
769
820
  end
@@ -6,8 +6,8 @@ module Sisimai
6
6
  module Mimecast
7
7
  class << self
8
8
  MessagesOf = {
9
- # https://community.mimecast.com/s/article/Mimecast-SMTP-Error-Codes-842605754
10
- # https://community.mimecast.com/s/article/email-security-cloud-gateway-mimecast-smtp-error-codes
9
+ # - https://community.mimecast.com/s/article/email-security-cloud-gateway-mimecast-smtp-error-codes
10
+ # - https://mimecastsupport.zendesk.com/hc/en-us/articles/34000709564691-Policies-Mimecast-SMTP-Error-Codes
11
11
  'authfailure' => [
12
12
  # - The inbound message has been rejected because the originated IP address isn't list-
13
13
  # ed in the published SPF records for the sending domain.
@@ -46,6 +46,8 @@ module Sisimai
46
46
  [550, 'local ct ip reputation - (reject)'],
47
47
  ],
48
48
  'blocked' => [
49
+ # - Sender address blocked.
50
+ # A Blocked Senders Policy has blocked the sender's IP address.
49
51
  # - The sender's IP address has been blocked by a Blocked Senders Policy.
50
52
  # - Remove the entry from the policy.
51
53
  [421, 'sender address blocked'],
@@ -74,9 +76,17 @@ module Sisimai
74
76
  # if rejected, causing the journal queue to grow.
75
77
  # - Check to confirm there are no significant time discrepancies on the mail server.
76
78
  # Discontinue journaling old messages past the expiry threshold.
77
- [550, 'Journal messages past the expiration'],
79
+ [550, 'journal messages past the expiration'],
78
80
  ],
79
81
  'failedstarttls' => [
82
+ # - SMTP inbound TLS has been enabled but no SSL certificate (or no valid certificate)
83
+ # has been selected to be used.
84
+ # - Delete or change the Secure Receipt or Secure Delivery policy enforcing TLS.
85
+ # Alternatively, ensure the certificates on the mail server haven't expired.
86
+ # If using a proxy server, ensure it isn't intercepting the traffic and modifying
87
+ # encryption parameters.
88
+ ["454", "tls not available due to temporary reason"],
89
+
80
90
  # - This email has been sent using SMTP, but TLS is required by policy.
81
91
  # - Delete or change the Secure Receipt or Secure Delivery policy enforcing TLS.
82
92
  # Alternatively, ensure the certificates on the mail server haven't expired. If using
@@ -199,6 +209,19 @@ module Sisimai
199
209
  [550, 'submitter failed to disabled'],
200
210
  [550, 'submitter failed to authenticate'],
201
211
  ],
212
+ 'spamdetected' => [
213
+ # - A signature was detected that could either be a virus, or a spam score over the
214
+ # maximum threshold. The spam score isn't available in the Administration Console. If
215
+ # you aren't a Mimecast customer but have emails rejected with this error code, con-
216
+ # tact the recipient to adjust their configuration and permit your address. If unsuc-
217
+ # cessful, your IT department can submit a request to review these email rejections
218
+ # via our Sender Feedback form.
219
+ # - Anti-virus checks cannot be bypassed. Contact the sender to see if they can stop
220
+ # these messages from being blocked. Anti-spam checks can be bypassed using a Per-
221
+ # mitted Senders or Auto Allow policy. Rejected emails can be viewed in your Outbound
222
+ # Activity and searching for the required email address.
223
+ [554, 'email rejected due to security policies'],
224
+ ],
202
225
  'systemerror' => [
203
226
  # - The Mimecast server is under maximum load.
204
227
  # - No action is required from the end-user. The message will retry 30 times and when
@@ -264,27 +287,14 @@ module Sisimai
264
287
  # - The sender must resend the message to a valid internal recipient address.
265
288
  [550, 'invalid recipient'],
266
289
  ],
267
- 'virusdetected' => [
268
- # - A signature was detected that could either be a virus, or a spam score over the
269
- # maximum threshold. The spam score isn't available in the Administration Console. If
270
- # you aren't a Mimecast customer but have emails rejected with this error code, con-
271
- # tact the recipient to adjust their configuration and permit your address. If unsuc-
272
- # cessful, your IT department can submit a request to review these email rejections
273
- # via our Sender Feedback form.
274
- # - Anti-virus checks cannot be bypassed. Contact the sender to see if they can stop
275
- # these messages from being blocked. Anti-spam checks can be bypassed using a Per-
276
- # mitted Senders or Auto Allow policy. Rejected emails can be viewed in your Outbound
277
- # Activity and searching for the required email address.
278
- [554, 'email rejected due to security policies'],
279
- ],
280
290
  }.freeze
281
291
 
282
292
  # Detect bounce reason from Mimecast
283
293
  # @param [Sisimai::Fact] argvs Decoded email object
284
294
  # @return [String] The bounce reason for mimecast.com
285
295
  def find(argvs)
286
- return argvs['reason'] unless argvs['reason'].empty?
287
- return '' unless Sisimai::SMTP::Reply.test(argvs['replycode'])
296
+ return argvs['reason'] if argvs['reason'].empty? == false
297
+ return '' if Sisimai::SMTP::Reply.test(argvs['replycode']) == false
288
298
 
289
299
  issuedcode = argvs['diagnosticcode'].downcase || ''
290
300
  esmtpreply = argvs['replycode'].to_i
@@ -294,12 +304,11 @@ module Sisimai
294
304
  # Try to match the error message with message patterns defined in "MessagesOf"
295
305
  MessagesOf[e].each do |f|
296
306
  # Find an error reason
297
- next unless esmtpreply == f[0]
298
- next unless issuedcode.include?(f[1])
307
+ next if esmtpreply != f[0] || issuedcode.include?(f[1]) == false
299
308
  reasontext = e
300
309
  break
301
310
  end
302
- break unless reasontext.empty?
311
+ break if reasontext.empty? == false
303
312
  end
304
313
 
305
314
  return reasontext
@@ -16,106 +16,86 @@ module Sisimai
16
16
  # @param [Sisimai::Fact] argvs Decoded email object
17
17
  # @return [String] The bounce reason for docomo.ne.jp
18
18
  def find(argvs)
19
- return argvs['reason'] unless argvs['reason'].empty?
19
+ return argvs['reason'] if argvs['reason'].empty? == false
20
20
  statuscode = argvs['deliverystatus'] || ''
21
21
  thecommand = argvs['command'] || ''
22
22
  esmtperror = argvs['diagnosticcode'].downcase || ''
23
- reasontext = ''
24
23
 
25
24
  # Check the value of Status: field, an SMTP Reply Code, and the SMTP Command
26
- if statuscode == '5.1.1' || statuscode == '5.0.911'
27
- # ----- Transcript of session follows -----
28
- # ... while talking to mfsmax.docomo.ne.jp.:
29
- # >>> RCPT To:<***@docomo.ne.jp>
30
- # <<< 550 Unknown user ***@docomo.ne.jp
31
- # 550 5.1.1 <***@docomo.ne.jp>... User unknown
32
- # >>> DATA
33
- # <<< 503 Bad sequence of commands
34
- reasontext = 'userunknown'
35
-
36
- elsif statuscode == '5.2.0'
37
- # ----- The following addresses had permanent fatal errors -----
38
- # <***@docomo.ne.jp>
39
- # (reason: 550 Unknown user ***@docomo.ne.jp)
40
- #
41
- # ----- Transcript of session follows -----
42
- # ... while talking to mfsmax.docomo.ne.jp.:
43
- # >>> DATA
44
- # <<< 550 Unknown user ***@docomo.ne.jp
45
- # 554 5.0.0 Service unavailable
46
- # ...
47
- # Final-Recipient: RFC822; ***@docomo.ne.jp
48
- # Action: failed
49
- # Status: 5.2.0
50
- reasontext = 'filtered'
25
+ #
26
+ # ----- Transcript of session follows -----
27
+ # ... while talking to mfsmax.docomo.ne.jp.:
28
+ # >>> RCPT To:<***@docomo.ne.jp>
29
+ # <<< 550 Unknown user ***@docomo.ne.jp
30
+ # 550 5.1.1 <***@docomo.ne.jp>... User unknown
31
+ # >>> DATA
32
+ # <<< 503 Bad sequence of commands
33
+ # ---------------------------------------------------------------------------------------
34
+ # ----- The following addresses had permanent fatal errors -----
35
+ # <***@docomo.ne.jp>
36
+ # (reason: 550 Unknown user ***@docomo.ne.jp)
37
+ #
38
+ # ----- Transcript of session follows -----
39
+ # ... while talking to mfsmax.docomo.ne.jp.:
40
+ # >>> DATA
41
+ # <<< 550 Unknown user ***@docomo.ne.jp
42
+ # 554 5.0.0 Service unavailable
43
+ # ...
44
+ # Final-Recipient: RFC822; ***@docomo.ne.jp
45
+ # Action: failed
46
+ # Status: 5.2.0
47
+ return 'userunknown' if statuscode == '5.1.1' || statuscode == '5.0.911'
48
+ return 'filtered' if statuscode == '5.2.0'
51
49
 
52
- else
50
+ MessagesOf.each_key do |e|
53
51
  # The value of "Diagnostic-Code:" field is not empty
54
- MessagesOf.each_key do |e|
55
- # - The key name is a bounce reason name
56
- # - https://github.com/sisimai/go-sisimai/issues/64
57
- # - After March 12, 2025, if an error message contains "550 Unknown user", the
58
- # bounce reason will be definitively "userunknown". This is because NTT DOCOMO
59
- # no longer rejects emails via SMTP for domain-specific rejection or specified
60
- # reception filters.
61
- next unless MessagesOf[e].any? { |a| esmtperror.include?(a) }
62
- reasontext = e
63
- break
64
- end
52
+ # - The key name is a bounce reason name
53
+ # - https://github.com/sisimai/go-sisimai/issues/64
54
+ # - After March 12, 2025, if an error message contains "550 Unknown user", the
55
+ # bounce reason will be definitively "userunknown". This is because NTT DOCOMO
56
+ # no longer rejects emails via SMTP for domain-specific rejection or specified
57
+ # reception filters.
58
+ return e if MessagesOf[e].any? { |a| esmtperror.include?(a) }
65
59
  end
66
60
 
67
- if reasontext.empty?
68
- # A bounce reason did not decide from a status code, an error message.
69
- if statuscode == '5.0.0'
70
- # Status: 5.0.0
71
- if thecommand == 'RCPT'
72
- # Your message to the following recipients cannot be delivered:
73
- #
74
- # <***@docomo.ne.jp>:
75
- # mfsmax.docomo.ne.jp [203.138.181.112]:
76
- # >>> RCPT TO:<***@docomo.ne.jp>
77
- # <<< 550 Unknown user ***@docomo.ne.jp
78
- # ...
79
- #
80
- # Final-Recipient: rfc822; ***@docomo.ne.jp
81
- # Action: failed
82
- # Status: 5.0.0
83
- # Remote-MTA: dns; mfsmax.docomo.ne.jp [203.138.181.112]
84
- # Diagnostic-Code: smtp; 550 Unknown user ***@docomo.ne.jp
85
- reasontext = 'userunknown'
86
-
87
- elsif thecommand == 'DATA'
88
- # <***@docomo.ne.jp>: host mfsmax.docomo.ne.jp[203.138.181.240] said:
89
- # 550 Unknown user ***@docomo.ne.jp (in reply to end of DATA
90
- # command)
91
- # ...
92
- # Final-Recipient: rfc822; ***@docomo.ne.jp
93
- # Original-Recipient: rfc822;***@docomo.ne.jp
94
- # Action: failed
95
- # Status: 5.0.0
96
- # Remote-MTA: dns; mfsmax.docomo.ne.jp
97
- # Diagnostic-Code: smtp; 550 Unknown user ***@docomo.ne.jp
98
- reasontext = 'rejected'
99
-
100
- else
101
- # Rejected by other SMTP commands: AUTH, MAIL,
102
- # もしもこのブロックを通過するNTTドコモからのエラーメッセージを見つけたら
103
- # https://github.com/sisimai/rb-sisimai/issues からご連絡ねがいます。
104
- #
105
- # If you found a error message from mfsmax.docomo.ne.jp which passes this block,
106
- # please open an issue at https://github.com/sisimai/rb-sisimai/issues .
107
- end
108
- else
109
- # Status: field is neither 5.0.0 nor values defined in code above
110
- # もしもこのブロックを通過するNTTドコモからのエラーメッセージを見つけたら
111
- # https://github.com/sisimai/rb-sisimai/issues からご連絡ねがいます。
112
- #
113
- # If you found a error message from mfsmax.docomo.ne.jp which passes this block,
114
- #
115
- end
61
+ # A bounce reason did not decide from a status code, an error message.
62
+ if statuscode == '5.0.0'
63
+ # Your message to the following recipients cannot be delivered:
64
+ #
65
+ # <***@docomo.ne.jp>:
66
+ # mfsmax.docomo.ne.jp [203.138.181.112]:
67
+ # >>> RCPT TO:<***@docomo.ne.jp>
68
+ # <<< 550 Unknown user ***@docomo.ne.jp
69
+ # ...
70
+ #
71
+ # Final-Recipient: rfc822; ***@docomo.ne.jp
72
+ # Action: failed
73
+ # Status: 5.0.0
74
+ # Remote-MTA: dns; mfsmax.docomo.ne.jp [203.138.181.112]
75
+ # Diagnostic-Code: smtp; 550 Unknown user ***@docomo.ne.jp
76
+ # -------------------------------------------------------------------------------------
77
+ # <***@docomo.ne.jp>: host mfsmax.docomo.ne.jp[203.138.181.240] said:
78
+ # 550 Unknown user ***@docomo.ne.jp (in reply to end of DATA
79
+ # command)
80
+ # ...
81
+ # Final-Recipient: rfc822; ***@docomo.ne.jp
82
+ # Original-Recipient: rfc822;***@docomo.ne.jp
83
+ # Action: failed
84
+ # Status: 5.0.0
85
+ # Remote-MTA: dns; mfsmax.docomo.ne.jp
86
+ # Diagnostic-Code: smtp; 550 Unknown user ***@docomo.ne.jp
87
+ return 'userunknown' if thecommand == 'RCPT'
88
+ return 'rejected' if thecommand == 'DATA'
116
89
  end
117
90
 
118
- return reasontext
91
+ # 1. Rejected by other SMTP commands: AUTH, MAIL,
92
+ # 2. Status: field is neither 5.0.0 nor values defined in code above
93
+ # もしもこのブロックを通過するNTTドコモからのエラーメッセージを見つけたら
94
+ # https://github.com/sisimai/rb-sisimai/issues からご連絡ねがいます。
95
+ #
96
+ # If you found a error message from mfsmax.docomo.ne.jp which passes this block,
97
+ # please open an issue at https://github.com/sisimai/rb-sisimai/issues .
98
+ return ""
119
99
  end
120
100
 
121
101
  end
@@ -21,7 +21,7 @@ module Sisimai
21
21
 
22
22
  MessagesOf.each_key do |e|
23
23
  # Try to match the error message with message patterns defined in $MessagesOf
24
- next unless MessagesOf[e].any? { |a| issuedcode.include?(a) }
24
+ next if MessagesOf[e].none? { |a| issuedcode.include?(a) }
25
25
  reasontext = e
26
26
  break
27
27
  end
@@ -101,7 +101,7 @@ module Sisimai
101
101
  # @return [String, Nil] The bounce reason at Spectrum
102
102
  # @since v4.25.8
103
103
  def find(argvs)
104
- return argvs['reason'] unless argvs['reason'].empty?
104
+ return argvs['reason'] if argvs['reason'].empty? == false
105
105
  issuedcode = argvs['diagnosticcode']
106
106
  reasontext = ''
107
107
  codenumber = if cv = issuedcode.match(/AUP#[-A-Za-z]*(\d{4})/) then cv[1].to_i else 0 end
@@ -22,12 +22,13 @@ module Sisimai
22
22
  'suspected spam', # https://service.mail.qq.com/detail/122/71
23
23
  'mail is rejected by recipients', # https://service.mail.qq.com/detail/122/92
24
24
  ],
25
- 'spandetected' => [
25
+ 'spamdetected' => [
26
26
  'spam is embedded in the email', # https://service.mail.qq.com/detail/122/59
27
27
  'mail content denied', # https://service.mail.qq.com/detail/122/171
28
28
  ],
29
29
  'speeding' => [
30
- 'mailbox unavailable or access denined', # https://service.mail.qq.com/detail/122/166
30
+ 'mailbox unavailable or access denined', # https://service.mail.qq.com/detail/122/166
31
+ "frequency of receiving messages is limited", # https://service.mail.qq.com/detail/122/1011
31
32
  ],
32
33
  'suspend' => [
33
34
  'is a deactivated mailbox', # http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=20022&&no=1000742
@@ -50,13 +51,13 @@ module Sisimai
50
51
  # @param [Sisimai::Fact] argvs Decoded email object
51
52
  # @return [String] The bounce reason at Tencent QQ
52
53
  def find(argvs)
53
- return argvs['reason'] unless argvs['reason'].empty?
54
+ return argvs['reason'] if argvs['reason'].empty? == false
54
55
  issuedcode = argvs['diagnosticcode'].downcase
55
56
  reasontext = ''
56
57
 
57
58
  MessagesOf.each_key do |e|
58
59
  MessagesOf[e].each do |f|
59
- next unless issuedcode.include?(f)
60
+ next if issuedcode.include?(f) == false
60
61
  reasontext = e
61
62
  break
62
63
  end
@@ -88,13 +88,13 @@ module Sisimai
88
88
  # https://www.postmastery.com/yahoo-postmaster/
89
89
  # @since v5.1.0
90
90
  def find(argvs)
91
- return argvs['reason'] unless argvs['reason'].empty?
91
+ return argvs['reason'] if argvs['reason'].empty? == false
92
92
  issuedcode = argvs['diagnosticcode'].downcase
93
93
  reasontext = ''
94
94
 
95
95
  MessagesOf.each_key do |e|
96
96
  MessagesOf[e].each do |f|
97
- next unless issuedcode.include?(f)
97
+ next if issuedcode.include?(f) == false
98
98
  reasontext = e
99
99
  break
100
100
  end
@@ -0,0 +1,72 @@
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 find() method when the value of "destination" of the object is ".zoho.com" or ".zoho.eu".
5
+ # This class is called only Sisimai::Fact class.
6
+ module Zoho
7
+ class << self
8
+ MessagesOf = {
9
+ 'authfailure' => [
10
+ # - <*******@zoho.com>: host smtpin.zoho.com[204.141.33.23] said: 550 5.7.1 Email
11
+ # rejected per DMARC policy for zoho.com
12
+ "Email rejected per DMARC policy",
13
+ ],
14
+ 'blocked' => [
15
+ # - mx.zoho.com[204.141.33.44]:25, delay=1202, delays=1200/0/0.91/0.30, dsn=4.7.1,
16
+ # status=deferred (host mx.zoho.com[204.141.33.44] said:
17
+ # 451 4.7.1 Greylisted, try again after some time (in reply to RCPT TO command))
18
+ "Greylisted, try again after some time",
19
+ ],
20
+ 'rejected' => [
21
+ # - <*******@zoho.com>: host smtpin.zoho.com[204.141.33.23] said: 554 5.7.1 Email
22
+ # cannot be delivered. Reason: Email flagged as Spam. (in reply to RCPT TO command)
23
+ # - <***@zoho.com>: host mx.zoho.com[136.143.183.44] said: 541 5.4.1 Mail rejected
24
+ # by destination domain (in reply to RCPT TO command)
25
+ "Email cannot be delivered. Reason: Email flagged as Spam",
26
+ "Mail rejected by destination domain",
27
+ ],
28
+ 'policyviolation' => [
29
+ # - <*******@zoho.com>: host smtpin.zoho.com[204.141.33.23] said: 554 5.7.7 Email
30
+ # policy violation detected (in reply to end of DATA command)
31
+ "Email policy violation detected",
32
+ "Mailbox delivery restricted by policy error",
33
+ ],
34
+ 'systemerror' => [
35
+ # - https://github.com/zoho/zohodesk-oas/blob/main/v1.0/EmailFailureAlert.json#L168
36
+ # 452 4.3.1 Temporary System Error
37
+ "Temporary System Error",
38
+ ],
39
+ 'userunknown' => [
40
+ # - <*******@zoho.com>: host smtpin.zoho.com[204.141.33.23] said:
41
+ # 550 5.1.1 User does not exist - <***@zoho.com> (in reply to RCPT TO command)
42
+ # - 552 5.1.1 <****@zoho.com> Mailbox delivery failure policy error
43
+ "User does not exist",
44
+ ],
45
+ 'virusdetected' => [
46
+ # - 552 5.7.1 virus **** detected by Zoho Mail
47
+ " detected by Zoho Mail",
48
+ ],
49
+ }.freeze
50
+
51
+ # Detect bounce reason from Apple iCloud Mail
52
+ # @param [Sisimai::Fact] argvs Decoded email object
53
+ # @return [String] The bounce reason for Apple
54
+ # @see
55
+ # @since v5.5.0
56
+ # - Zoho Mail: https://www.zoho.com/mail/
57
+ # - Reasons an email is marked as Spam: https://www.zoho.com/mail/help/spam-reason.html
58
+ # - https://github.com/zoho/zohodesk-oas/blob/main/v1.0/EmailFailureAlert.json
59
+ # - Zoho SMTP Error Codes | SMTP Field Manual: https://smtpfieldmanual.com/provider/zoho
60
+ def find(argvs)
61
+ return '' if argvs.nil? || argvs['diagnosticcode'].size == 0
62
+ MessagesOf.each_key do |e|
63
+ return e if MessagesOf[e].any? { |a| argvs['diagnosticcode'].include?(a) }
64
+ end
65
+ return ''
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
72
+