sisimai 5.7.0 → 5.7.1

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +15 -0
  3. data/README-JA.md +8 -8
  4. data/README.md +8 -8
  5. data/lib/sisimai/arf.rb +2 -1
  6. data/lib/sisimai/eb.rb +116 -0
  7. data/lib/sisimai/fact.rb +24 -17
  8. data/lib/sisimai/lda.rb +20 -18
  9. data/lib/sisimai/lhost/amazonses.rb +11 -10
  10. data/lib/sisimai/lhost/courier.rb +4 -3
  11. data/lib/sisimai/lhost/domino.rb +2 -1
  12. data/lib/sisimai/lhost/einsundeins.rb +3 -2
  13. data/lib/sisimai/lhost/exchange2003.rb +8 -7
  14. data/lib/sisimai/lhost/exchange2007.rb +14 -13
  15. data/lib/sisimai/lhost/exim.rb +7 -6
  16. data/lib/sisimai/lhost/ezweb.rb +4 -3
  17. data/lib/sisimai/lhost/fml.rb +4 -3
  18. data/lib/sisimai/lhost/gmail.rb +10 -9
  19. data/lib/sisimai/lhost/googlegroups.rb +3 -2
  20. data/lib/sisimai/lhost/googleworkspace.rb +2 -1
  21. data/lib/sisimai/lhost/imailserver.rb +3 -2
  22. data/lib/sisimai/lhost/kddi.rb +4 -3
  23. data/lib/sisimai/lhost/notes.rb +2 -1
  24. data/lib/sisimai/lhost/postfix.rb +7 -6
  25. data/lib/sisimai/lhost/qmail.rb +10 -9
  26. data/lib/sisimai/lhost/sendmail.rb +4 -3
  27. data/lib/sisimai/lhost/trendmicro.rb +2 -1
  28. data/lib/sisimai/lhost/v5sendmail.rb +2 -1
  29. data/lib/sisimai/lhost/verizon.rb +3 -2
  30. data/lib/sisimai/reason/authfailure.rb +6 -5
  31. data/lib/sisimai/reason/badreputation.rb +5 -4
  32. data/lib/sisimai/reason/blocked.rb +6 -5
  33. data/lib/sisimai/reason/contenterror.rb +6 -5
  34. data/lib/sisimai/reason/delivered.rb +3 -2
  35. data/lib/sisimai/reason/emailtoolarge.rb +6 -5
  36. data/lib/sisimai/reason/expired.rb +3 -2
  37. data/lib/sisimai/reason/failedstarttls.rb +5 -3
  38. data/lib/sisimai/reason/feedback.rb +2 -1
  39. data/lib/sisimai/reason/filtered.rb +9 -8
  40. data/lib/sisimai/reason/hasmoved.rb +5 -4
  41. data/lib/sisimai/reason/hostunknown.rb +5 -4
  42. data/lib/sisimai/reason/mailboxfull.rb +7 -6
  43. data/lib/sisimai/reason/mailererror.rb +3 -2
  44. data/lib/sisimai/reason/networkerror.rb +3 -2
  45. data/lib/sisimai/reason/norelaying.rb +4 -3
  46. data/lib/sisimai/reason/notaccept.rb +5 -4
  47. data/lib/sisimai/reason/notcompliantrfc.rb +4 -3
  48. data/lib/sisimai/reason/onhold.rb +8 -7
  49. data/lib/sisimai/reason/policyviolation.rb +7 -6
  50. data/lib/sisimai/reason/ratelimited.rb +5 -4
  51. data/lib/sisimai/reason/rejected.rb +18 -14
  52. data/lib/sisimai/reason/requireptr.rb +5 -4
  53. data/lib/sisimai/reason/securityerror.rb +4 -3
  54. data/lib/sisimai/reason/spamdetected.rb +6 -5
  55. data/lib/sisimai/reason/suppressed.rb +4 -3
  56. data/lib/sisimai/reason/suspend.rb +4 -3
  57. data/lib/sisimai/reason/syntaxerror.rb +4 -3
  58. data/lib/sisimai/reason/systemerror.rb +3 -2
  59. data/lib/sisimai/reason/systemfull.rb +4 -3
  60. data/lib/sisimai/reason/undefined.rb +2 -1
  61. data/lib/sisimai/reason/userunknown.rb +13 -9
  62. data/lib/sisimai/reason/vacation.rb +2 -1
  63. data/lib/sisimai/reason/virusdetected.rb +6 -5
  64. data/lib/sisimai/reason.rb +45 -40
  65. data/lib/sisimai/rfc1894.rb +8 -2
  66. data/lib/sisimai/rfc2045.rb +6 -3
  67. data/lib/sisimai/rfc3464/thirdparty.rb +10 -9
  68. data/lib/sisimai/rfc3834.rb +4 -2
  69. data/lib/sisimai/rhost/aol.rb +3 -2
  70. data/lib/sisimai/rhost/apple.rb +12 -11
  71. data/lib/sisimai/rhost/cloudflare.rb +3 -2
  72. data/lib/sisimai/rhost/cox.rb +38 -37
  73. data/lib/sisimai/rhost/facebook.rb +17 -16
  74. data/lib/sisimai/rhost/franceptt.rb +39 -38
  75. data/lib/sisimai/rhost/godaddy.rb +35 -34
  76. data/lib/sisimai/rhost/google.rb +22 -21
  77. data/lib/sisimai/rhost/gsuite.rb +8 -7
  78. data/lib/sisimai/rhost/iua.rb +11 -10
  79. data/lib/sisimai/rhost/kddi.rb +3 -2
  80. data/lib/sisimai/rhost/messagelabs.rb +13 -12
  81. data/lib/sisimai/rhost/microsoft.rb +33 -32
  82. data/lib/sisimai/rhost/mimecast.rb +18 -17
  83. data/lib/sisimai/rhost/nttdocomo.rb +10 -9
  84. data/lib/sisimai/rhost/outlook.rb +3 -2
  85. data/lib/sisimai/rhost/spectrum.rb +19 -18
  86. data/lib/sisimai/rhost/tencent.rb +10 -9
  87. data/lib/sisimai/rhost/yahooinc.rb +11 -10
  88. data/lib/sisimai/rhost/zoho.rb +8 -7
  89. data/lib/sisimai/smtp/command.rb +13 -8
  90. data/lib/sisimai/smtp/failure.rb +9 -8
  91. data/lib/sisimai/smtp/reply.rb +23 -22
  92. data/lib/sisimai/smtp/status.rb +141 -140
  93. data/lib/sisimai/smtp/transcript.rb +3 -2
  94. data/lib/sisimai/version.rb +1 -1
  95. data/lib/sisimai.rb +2 -1
  96. data/set-of-emails/maildir/bsd/lhost-postfix-81.eml +130 -0
  97. data/set-of-emails/should-not-crash/go-423-deeply-nested-mime-parts.eml +20050 -0
  98. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7df8c7a329d0b47c042e69fb471062991ec6559ed7d231a25ae693bc8f00809a
4
- data.tar.gz: b09714499bb39b23f62dc6b6c5e0a94767688df4305737d9343c6c603b0bfec6
3
+ metadata.gz: fe26d7361ec6d30cae438f4ee17e01a533d4ce63079f37e3d3912f7addd438a6
4
+ data.tar.gz: 915a7f5d1543537380a0919f2d7300cbe2899fb80fe33fa402d5b94f131d5375
5
5
  SHA512:
6
- metadata.gz: cff9ac363a2a70bd91e376cd1150cff122e17d9797288f2c8042e3d3c74009f014abd98e9a46c4eeb7d51e1ffaceed62340889075e969b1c9341facde1027d25
7
- data.tar.gz: d36372f77fdf9767b7b51b785580c3a3fa4f5b1ed582ad2d265390dacdd6babb248260dfccf4d879959cf9fec7dafce6fc71454bc5c96114b729ceab432436e7
6
+ metadata.gz: b5a929ebc2d9ee903c1374e27f235753646dcbed777a096d0fe03ca69658041d9afcb064b8d16fb0b42e68ba87f4a5590900053781eb004aa1c637e0d157722b
7
+ data.tar.gz: 9dd782811c37de36a02073ec339a191381574897d4e579422b583e7dd23625ed61424486245fd9efc1c705f2be506b5d91706617a3446da857241063116990aa
data/ChangeLog.md CHANGED
@@ -4,6 +4,21 @@ RELEASE NOTES for Ruby version of Sisimai
4
4
  - download: "https://rubygems.org/gems/sisimai"
5
5
  - document: "https://libsisimai.org/"
6
6
 
7
+ v5.7.1
8
+ ---------------------------------------------------------------------------------------------------
9
+ - release: "Fri, 17 Jul 2026 13:22:22 +0900 (JST)"
10
+ - version: "5.7.1"
11
+ - changes:
12
+ - **Bug fixes**
13
+ - Fix duplicated SMTP command `HELO` in `Sisimai::SMTP::Command`.
14
+ - **Mitigation for potential DoS vectors**
15
+ - #441 Limit the nesting depth of MIME parts in Sisimai::RFC2045 class.
16
+ - **Code improvements**
17
+ - New class `Sisimai::Eb` for keeping constants.
18
+ - #443 `Sisimai::Eb::Re****` Bounce reason names.
19
+ - #447 `Sisimai::Eb::Ce****` SMTP commands.
20
+ - #448 `Sisimai::Eb::Ae****` Action field values.
21
+
7
22
  v5.7.0
8
23
  ---------------------------------------------------------------------------------------------------
9
24
  - release: "Mon, 22 Jun 2026 16:22:22 +0900 (JST)"
data/README-JA.md CHANGED
@@ -116,10 +116,10 @@ Install
116
116
  ### From RubyGems.org
117
117
  ```shell
118
118
  $ sudo gem install sisimai
119
- Fetching: sisimai-5.7.0.gem (100%)
120
- Successfully installed sisimai-5.7.0
121
- Parsing documentation for sisimai-5.7.0
122
- Installing ri documentation for sisimai-5.7.0
119
+ Fetching: sisimai-5.7.1.gem (100%)
120
+ Successfully installed sisimai-5.7.1
121
+ Parsing documentation for sisimai-5.7.1
122
+ Installing ri documentation for sisimai-5.7.1
123
123
  Done installing documentation for sisimai after 6 seconds
124
124
  1 gem installed
125
125
  ```
@@ -147,13 +147,13 @@ if [ -d "/usr/local/jr" ]; then \
147
147
  ...
148
148
  3 gems installed
149
149
  /opt/local/bin/rake install
150
- sisimai 5.7.0 built to pkg/sisimai-5.7.0.gem.
151
- sisimai (5.7.0) installed.
150
+ sisimai 5.7.1 built to pkg/sisimai-5.7.1.gem.
151
+ sisimai (5.7.1) installed.
152
152
  if [ -d "/usr/local/jr" ]; then \
153
153
  PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
154
154
  fi
155
- sisimai 5.7.0 built to pkg/sisimai-5.7.0-java.gem.
156
- sisimai (5.7.0) installed.
155
+ sisimai 5.7.1 built to pkg/sisimai-5.7.1-java.gem.
156
+ sisimai (5.7.1) installed.
157
157
  ```
158
158
 
159
159
  Usage
data/README.md CHANGED
@@ -115,10 +115,10 @@ Install
115
115
  ### From RubyGems
116
116
  ```shell
117
117
  $ sudo gem install sisimai
118
- Fetching: sisimai-5.7.0.gem (100%)
119
- Successfully installed sisimai-5.7.0
120
- Parsing documentation for sisimai-5.7.0
121
- Installing ri documentation for sisimai-5.7.0
118
+ Fetching: sisimai-5.7.1.gem (100%)
119
+ Successfully installed sisimai-5.7.1
120
+ Parsing documentation for sisimai-5.7.1
121
+ Installing ri documentation for sisimai-5.7.1
122
122
  Done installing documentation for sisimai after 6 seconds
123
123
  1 gem installed
124
124
  ```
@@ -146,13 +146,13 @@ if [ -d "/usr/local/jr" ]; then \
146
146
  ...
147
147
  3 gems installed
148
148
  /opt/local/bin/rake install
149
- sisimai 5.7.0 built to pkg/sisimai-5.7.0.gem.
150
- sisimai (5.7.0) installed.
149
+ sisimai 5.7.1 built to pkg/sisimai-5.7.1.gem.
150
+ sisimai (5.7.1) installed.
151
151
  if [ -d "/usr/local/jr" ]; then \
152
152
  PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
153
153
  fi
154
- sisimai 5.7.0 built to pkg/sisimai-5.7.0-java.gem.
155
- sisimai (5.7.0) installed.
154
+ sisimai 5.7.1 built to pkg/sisimai-5.7.1-java.gem.
155
+ sisimai (5.7.1) installed.
156
156
  ```
157
157
 
158
158
  Usage
data/lib/sisimai/arf.rb CHANGED
@@ -2,6 +2,7 @@ module Sisimai
2
2
  # Sisimai::ARF is a decoder for the email returned as a FeedBack Loop report message.
3
3
  module ARF
4
4
  class << self
5
+ require 'sisimai/eb'
5
6
  require 'sisimai/lhost'
6
7
  require 'sisimai/rfc5322'
7
8
 
@@ -220,7 +221,7 @@ module Sisimai
220
221
  # Tidy up the error message in e.Diagnosis, Try to detect the bounce reason.
221
222
  j += 1
222
223
  e["diagnosis"] = e["diagnosis"] + anotherone
223
- e["reason"] = "feedback"
224
+ e["reason"] = Sisimai::Eb::ReFEED
224
225
  e["rhost"] = remotehost
225
226
  e["lhost"] = reportedby
226
227
  e["date"] = timestamp0
data/lib/sisimai/eb.rb ADDED
@@ -0,0 +1,116 @@
1
+ module Sisimai
2
+ # Sisimai::Eb - Package "eb" provides constants for the email bounce.
3
+ module Eb
4
+ # _ ______
5
+ # ___| |__ / / _ \ ___ __ _ ___ ___ _ __
6
+ # / _ \ '_ \ / /| |_) / _ \/ _` / __|/ _ \| '_ \
7
+ # | __/ |_) / / | _ < __/ (_| \__ \ (_) | | | |
8
+ # \___|_.__/_/ |_| \_\___|\__,_|___/\___/|_| |_|
9
+ # bounce reason names
10
+ ReAUTH = "AuthFailure"
11
+ ReFAMA = "BadReputation"
12
+ ReBLOC = "Blocked"
13
+ ReBODY = "ContentError"
14
+ ReSENT = "Delivered"
15
+ ReSIZE = "EmailTooLarge"
16
+ ReTIME = "Expired"
17
+ ReTTLS = "FailedSTARTTLS"
18
+ ReFEED = "Feedback"
19
+ ReFILT = "Filtered"
20
+ ReMOVE = "HasMoved"
21
+ ReHOST = "HostUnknown"
22
+ ReFULL = "MailboxFull"
23
+ ReUNIX = "MailerError"
24
+ ReINET = "NetworkError"
25
+ RePASS = "NoRelaying"
26
+ Re00MX = "NotAccept"
27
+ ReNRFC = "NotCompliantRFC"
28
+ Re___1 = "OnHold"
29
+ ReWONT = "PolicyViolation"
30
+ ReFROM = "Rejected"
31
+ ReQPTR = "RequirePTR"
32
+ ReRATE = "RateLimited"
33
+ ReSAFE = "SecurityError"
34
+ ReSPAM = "SpamDetected"
35
+ ReSTOP = "Suppressed"
36
+ ReQUIT = "Suspend"
37
+ ReCOMM = "SyntaxError"
38
+ RePROC = "SystemError"
39
+ ReDISK = "SystemFull"
40
+ Re___0 = "Undefined"
41
+ ReUSER = "UserUnknown"
42
+ ReAWAY = "Vacation"
43
+ ReEXEC = "VirusDetected"
44
+
45
+ # _ ______ _
46
+ # ___| |__ / / ___|___ _ __ ___ _ __ ___ __ _ _ __ __| |
47
+ # / _ \ '_ \ / / | / _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` |
48
+ # | __/ |_) / /| |__| (_) | | | | | | | | | | | (_| | | | | (_| |
49
+ # \___|_.__/_/ \____\___/|_| |_| |_|_| |_| |_|\__,_|_| |_|\__,_|
50
+ CeHELO = "HELO"
51
+ CeEHLO = "EHLO"
52
+ CeMAIL = "MAIL"
53
+ CeRCPT = "RCPT"
54
+ CeDATA = "DATA"
55
+ CeQUIT = "QUIT"
56
+ CeRSET = "RSET"
57
+ CeNOOP = "NOOP"
58
+ CeVRFY = "VRFY"
59
+ CeETRN = "ETRN"
60
+ CeEXPN = "EXPN"
61
+ CeHELP = "HELP"
62
+ CeAUTH = "AUTH"
63
+ CeTTLS = "STARTTLS"
64
+ CeXFWD = "XFORWARD"
65
+ CeCONN = "CONN" # CONN is a pseudo SMTP command used only in Sisimai
66
+
67
+ # _ ___ _ _
68
+ # ___| |__ / / \ ___| |_(_) ___ _ __
69
+ # / _ \ '_ \ / / _ \ / __| __| |/ _ \| '_ \
70
+ # | __/ |_) / / ___ \ (__| |_| | (_) | | | |
71
+ # \___|_.__/_/_/ \_\___|\__|_|\___/|_| |_|
72
+ #
73
+ # https://datatracker.ietf.org/doc/html/rfc3464#page-16
74
+ # 2.3.3 Action field
75
+ # The Action field indicates the action performed by the Reporting-MTA as a result of its attempt
76
+ # to deliver the message to this recipient address. This field MUST be present for each recipient
77
+ # named in the DSN.
78
+ #
79
+ # The syntax for the action-field is:
80
+ # action-field = "Action" ":" action-value
81
+ # action-value = "failed" / "delayed" / "delivered" / "relayed" / "expanded"
82
+ #
83
+ # The action-value may be spelled in any combination of upper and lower case characters.
84
+ #
85
+ # "failed" indicates that the message could not be delivered to the recipient.
86
+ # The Reporting MTA has abandoned any attempts to deliver the message to this
87
+ # recipient. No further notifications should be expected.
88
+ #
89
+ # "delayed" indicates that the Reporting MTA has so far been unable to deliver or relay the
90
+ # message, but it will continue to attempt to do so. Additional notification
91
+ # messages may be issued as the message is further delayed or successfully
92
+ # delivered, or if delivery attempts are later abandoned.
93
+ #
94
+ # "delivered" indicates that the message was successfully delivered to the recipient address
95
+ # specified by the sender, which includes "delivery" to a mailing list exploder.
96
+ # It does not indicate that the message has been read. This is a terminal state
97
+ # and no further DSN for this recipient should be expected.
98
+ #
99
+ # "relayed" indicates that the message has been relayed or gatewayed into an environment
100
+ # that does not accept responsibility for generating DSNs upon successful delivery.
101
+ # This action-value SHOULD NOT be used unless the sender has requested notification
102
+ # of successful delivery for this recipient.
103
+ #
104
+ # "expanded" indicates that the message has been successfully delivered to the recipient
105
+ # address as specified by the sender, and forwarded by the Reporting-MTA beyond
106
+ # that destination to multiple additional recipient addresses. An action-value of
107
+ # "expanded" differs from "delivered" in that "expanded" is not a terminal state.
108
+ # Further "failed" and/or "delayed" notifications may be provided.
109
+ AeFAIL = "failed"
110
+ AeSTAY = "delayed"
111
+ AeSENT = "delivered"
112
+ AePASS = "relayed"
113
+ AeEXPN = "expanded"
114
+ end
115
+ end
116
+
data/lib/sisimai/fact.rb CHANGED
@@ -15,6 +15,7 @@ module Sisimai
15
15
  require 'sisimai/string'
16
16
  require 'sisimai/rhost'
17
17
  require 'sisimai/lda'
18
+ require 'sisimai/eb'
18
19
 
19
20
  @@rwaccessors = [
20
21
  :action, # [String] The value of Action: header
@@ -122,7 +123,7 @@ module Sisimai
122
123
  while e = deliveries.shift do
123
124
  # Create parameters for each Sisimai::Fact object
124
125
  next if e['recipient'].size < 5
125
- next if ! argvs[:vacation] && e['reason'] == 'vacation'
126
+ next if ! argvs[:vacation] && e['reason'] == Sisimai::Eb::ReAWAY
126
127
  next if ! argvs[:delivered] && e['status'].start_with?('2.')
127
128
 
128
129
  thing = {} # To be passed to each accessor of Sisimai::Fact
@@ -353,7 +354,7 @@ module Sisimai
353
354
  piece['diagnosticcode'] = piece['diagnosticcode'].force_encoding('UTF-8').scrub('?')
354
355
  end
355
356
 
356
- piece["diagnostictype"] = "X-UNIX" if piece["reason"] == "mailererror"
357
+ piece["diagnostictype"] = "X-UNIX" if piece["reason"] == Sisimai::Eb::ReUNIX
357
358
  if piece["diagnostictype"].empty?
358
359
  piece["diagnostictype"] = "SMTP" if %w[feedback vacation].include?(piece["reason"]) == false
359
360
  end
@@ -363,7 +364,7 @@ module Sisimai
363
364
  # - <<< 503-5.5.1 RCPT first. A mail transaction protocol command was issued ...
364
365
  # - RCPT first (in reply to DATA command)
365
366
  piece['command'] = '' if Sisimai::SMTP::Command.test(piece['command']) == false
366
- piece['command'] = 'RCPT' if piece['diagnosticcode'].include?('RCPT first')
367
+ piece['command'] = Sisimai::Eb::CeRCPT if piece['diagnosticcode'].include?('RCPT first')
367
368
 
368
369
  # Create parameters for the constructor
369
370
  as = Sisimai::Address.new(piece['addresser']) || next; next if as.void
@@ -384,14 +385,14 @@ module Sisimai
384
385
  ea.each { |q| thing[q] = piece[q] if thing[q].nil? || thing[q].empty? }
385
386
 
386
387
  # Other accessors
387
- thing['bogus'] = 0
388
+ thing['bogus'] = -1
388
389
  thing['catch'] = piece['catch'] || nil
389
390
  thing["feedbackid"] = ""
390
391
  thing['hardbounce'] = piece['hardbounce']
391
392
  thing['replycode'] = Sisimai::SMTP::Reply.find(piece['diagnosticcode']) if thing['replycode'].empty?
392
393
  thing['timestamp'] = TimeModule.parse(::Time.at(piece['timestamp']).to_s)
393
394
  thing['timezoneoffset'] = piece['timezoneoffset'] || '+0000'
394
- thing['toxic'] = 0
395
+ thing['toxic'] = -1
395
396
  ea.each { |q| thing[q] = piece[q] if thing[q].empty? }
396
397
 
397
398
  # ALIAS
@@ -422,25 +423,30 @@ module Sisimai
422
423
  while true
423
424
  if thing["reason"].empty? || RetryIndex[thing["reason"]]
424
425
  # The value of "reason" is empty or is needed to check with other values again
425
- re = thing["reason"].empty? ? "undefined" : thing["reason"]
426
+ re = thing["reason"].empty? ? Sisimai::Eb::Re___0 : thing["reason"]
426
427
  cr = Sisimai::LDA.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
427
428
  cr = Sisimai::Rhost.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
428
429
  cr = Sisimai::Reason.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
429
- thing["reason"] = thing["diagnosticcode"].size > 0 ? "onhold" : re
430
+ thing["reason"] = thing["diagnosticcode"].size > 0 ? Sisimai::Eb::Re___1 : re
430
431
  break
431
432
  end
432
433
  break
433
434
  end
434
435
 
435
- # HARDBOUNCE: Set the value of "hardbounce", default value of "bouncebounce" is false
436
- if thing['reason'] == 'delivered' || thing['reason'] == 'feedback' || thing['reason'] == 'vacation'
437
- # Delete the value of ReplyCode when the Reason is "feedback" or "vacation"
438
- thing['replycode'] = '' if thing['reason'] != 'delivered'
439
- else
440
- # The reason is not "delivered", or "feedback", or "vacation"
436
+ while true
437
+ # HARDBOUNCE: Set the value of "hardbounce", default value of "bouncebounce" is false
438
+ break if thing['reason'] == Sisimai::Eb::ReSENT
439
+ if thing['reason'] == Sisimai::Eb::ReFEED || thing['reason'] == Sisimai::Eb::ReAWAY
440
+ # Delete the value of ReplyCode when the Reason is "Feedback" or "Vacation"
441
+ thing['replycode'] = ""
442
+ break
443
+ end
444
+
445
+ # The reason is not "Delivered", or "Feedback", or "Vacation"
441
446
  smtperrors = "#{piece['deliverystatus']} #{piece['diagnosticcode']}"
442
447
  smtperrors = '' if smtperrors.size < 4
443
448
  thing['hardbounce'] = Sisimai::SMTP::Failure.is_hardbounce(thing['reason'], smtperrors)
449
+ break
444
450
  end
445
451
 
446
452
  # DELIVERYSTATUS: Set a pseudo status code if the value of "deliverystatus" is empty
@@ -472,10 +478,10 @@ module Sisimai
472
478
  thing['action'] = ox[2]
473
479
  end
474
480
  end
475
- thing["action"] = "" if thing["action"].nil?
476
- thing["action"] = "delivered" if thing["action"].empty? && thing["reason"] == "delivered"
477
- thing["action"] = "delayed" if thing["action"].empty? && thing["reason"] == "expired"
478
- thing["action"] = "failed" if thing["action"].empty? && cx[0] == "4" || cx[0] == "5"
481
+ thing["action"] = "" if thing["action"].nil?
482
+ thing["action"] = Sisimai::Eb::AeSENT if thing["action"].empty? && thing["reason"] == Sisimai::Eb::ReSENT
483
+ thing["action"] = Sisimai::Eb::AeSTAY if thing["action"].empty? && thing["reason"] == Sisimai::Eb::ReTIME
484
+ thing["action"] = Sisimai::Eb::AeFAIL if thing["action"].empty? && cx[0] == "4" || cx[0] == "5"
479
485
 
480
486
  if thing["replycode"].size > 0
481
487
  # Fill empty values: ["SMTP Command", "DSN", "Reason"]
@@ -489,6 +495,7 @@ module Sisimai
489
495
 
490
496
  # Feedback-ID: 1.us-west-2.QHuyeCQrGtIIMGKQfVdUhP9hCQR2LglVOrRamBc+Prk=:AmazonSES
491
497
  thing["feedbackid"] = rfc822data["feedback-id"] || ""
498
+ thing["reason"] = thing["reason"].downcase
492
499
 
493
500
  listoffact << Sisimai::Fact.new(thing)
494
501
  end
data/lib/sisimai/lda.rb CHANGED
@@ -2,6 +2,8 @@ module Sisimai
2
2
  # Sisimai::LDA - Error message decoder for LDA
3
3
  module LDA
4
4
  class << self
5
+ require 'sisimai/eb'
6
+
5
7
  LocalAgent = {
6
8
  # Each error message should be a lower-cased string
7
9
  # dovecot/src/deliver/deliver.c
@@ -19,20 +21,20 @@ module Sisimai
19
21
  # Each error message should be a lower-cased string
20
22
  "dovecot" => {
21
23
  # dovecot/src/deliver/mail-send.c:94
22
- "mailboxfull" => [
24
+ Sisimai::Eb::ReFULL => [
23
25
  "not enough disk space",
24
26
  "quota exceeded", # Dovecot 1.2 dovecot/src/plugins/quota/quota.c
25
27
  "quota exceeded (mailbox for user is full)", # dovecot/src/plugins/quota/quota.c
26
28
  ],
27
- "userunknown" => ["mailbox doesn't exist: "],
29
+ Sisimai::Eb::ReUSER => ["mailbox doesn't exist: "],
28
30
  },
29
31
  "mail.local" => {
30
- "mailboxfull" => [
32
+ Sisimai::Eb::ReFULL => [
31
33
  "disc quota exceeded",
32
34
  "mailbox full or quota exceeded",
33
35
  ],
34
- "systemerror" => ["temporary file write error"],
35
- "userunknown" => [
36
+ Sisimai::Eb::RePROC => ["temporary file write error"],
37
+ Sisimai::Eb::ReUSER => [
36
38
  ": invalid mailbox path",
37
39
  ": unknown user:",
38
40
  ": user missing home directory",
@@ -40,23 +42,23 @@ module Sisimai
40
42
  ],
41
43
  },
42
44
  "procmail" => {
43
- "mailboxfull" => ["quota exceeded while writing", "user over quota"],
44
- "systemerror" => ["service unavailable"],
45
- "systemfull" => ["no space left to finish writing"],
45
+ Sisimai::Eb::ReFULL => ["quota exceeded while writing", "user over quota"],
46
+ Sisimai::Eb::RePROC => ["service unavailable"],
47
+ Sisimai::Eb::ReDISK => ["no space left to finish writing"],
46
48
  },
47
49
  "maildrop" => {
48
- "userunknown" => ["cannot find system user", "invalid user specified."],
49
- "mailboxfull" => ["maildir over quota."],
50
+ Sisimai::Eb::ReUSER => ["cannot find system user", "invalid user specified."],
51
+ Sisimai::Eb::ReFULL => ["maildir over quota."],
50
52
  },
51
53
  "vpopmail" => {
52
- "filtered" => ["user does not exist, but will deliver to "],
53
- "mailboxfull" => ["domain is over quota", "user is over quota"],
54
- "suspend" => ["account is locked email bounced"],
55
- "userunknown" => ["sorry, no mailbox here by that name."],
54
+ Sisimai::Eb::ReFILT => ["user does not exist, but will deliver to "],
55
+ Sisimai::Eb::ReFULL => ["domain is over quota", "user is over quota"],
56
+ Sisimai::Eb::ReQUIT => ["account is locked email bounced"],
57
+ Sisimai::Eb::ReUSER => ["sorry, no mailbox here by that name."],
56
58
  },
57
59
  "vmailmgr" => {
58
- "mailboxfull" => ["delivery failed due to system quota violation"],
59
- "userunknown" => [
60
+ Sisimai::Eb::ReFULL => ["delivery failed due to system quota violation"],
61
+ Sisimai::Eb::ReUSER => [
60
62
  "invalid or unknown base user or domain",
61
63
  "invalid or unknown virtual user",
62
64
  "user name does not refer to a virtual user",
@@ -70,7 +72,7 @@ module Sisimai
70
72
  def find(argvs)
71
73
  return "" if argvs.nil?
72
74
  return "" if argvs["diagnosticcode"].empty?
73
- return "" if argvs["command"] != "" && argvs["command"] != "DATA"
75
+ return "" if argvs["command"] != "" && argvs["command"] != Sisimai::Eb::CeDATA
74
76
 
75
77
  deliversby = "" # [String] Local Delivery Agent name
76
78
  reasontext = "" # [String] Error reason
@@ -89,7 +91,7 @@ module Sisimai
89
91
  reasontext = e; break
90
92
  end
91
93
 
92
- reasontext = "mailererror" if reasontext.empty?
94
+ reasontext = Sisimai::Eb::ReUNIX if reasontext.empty?
93
95
  return reasontext
94
96
  end
95
97
  end
@@ -42,16 +42,17 @@ module Sisimai::Lhost
42
42
  # Transient/ContentRejected -- message you sent contains content that the provider doesn't allow
43
43
  # Transient/AttachmentRejected the message contained an unacceptable attachment
44
44
  class << self
45
+ require 'sisimai/eb'
45
46
  require 'sisimai/lhost'
46
47
 
47
48
  ReasonPair = {
48
- "Suppressed" => "suppressed",
49
- "OnAccountSuppressionList" => "suppressed",
50
- "General" => "onhold",
51
- "MailboxFull" => "mailboxfull",
52
- "MessageTooLarge" => "emailtoolarge",
53
- "ContentRejected" => "contenterror",
54
- "AttachmentRejected" => "securityerror",
49
+ "Suppressed" => Sisimai::Eb::ReSTOP,
50
+ "OnAccountSuppressionList" => Sisimai::Eb::ReSTOP,
51
+ "General" => Sisimai::Eb::Re___1,
52
+ "MailboxFull" => Sisimai::Eb::ReFULL,
53
+ "MessageTooLarge" => Sisimai::Eb::ReSIZE,
54
+ "ContentRejected" => Sisimai::Eb::ReBODY,
55
+ "AttachmentRejected" => Sisimai::Eb::ReSAFE,
55
56
  }.freeze
56
57
 
57
58
  # @abstract Decodes the bounce message from Amazon SES
@@ -164,7 +165,7 @@ module Sisimai::Lhost
164
165
  v = dscontents[-1]
165
166
  end
166
167
  v["recipient"] = e["emailAddress"]
167
- v["reason"] = "feedback"
168
+ v["reason"] = Sisimai::Eb::ReFEED
168
169
  v["feedbacktype"] = p["complaintFeedbackType"]
169
170
  v["date"] = p["timestamp"]
170
171
  v["diagnosis"] = sprintf('"feedbackid":"%s", "useragent":"%s"}', p["feedbackId"], p["userAgent"])
@@ -181,8 +182,8 @@ module Sisimai::Lhost
181
182
  v = dscontents[-1]
182
183
  end
183
184
  v["recipient"] = e
184
- v["reason"] = "delivered"
185
- v["action"] = "delivered"
185
+ v["reason"] = Sisimai::Eb::ReSENT
186
+ v["action"] = Sisimai::Eb::AeSENT
186
187
  v["date"] = p["timestamp"]
187
188
  v["lhost"] = Sisimai::RFC1123.find(p["reportingMTA"])
188
189
  v["diagnosis"] = p["smtpResponse"]
@@ -3,6 +3,7 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module Courier
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
 
8
9
  # https://www.courier-mta.org/courierdsn.html
@@ -14,12 +15,12 @@ module Sisimai::Lhost
14
15
  }.freeze
15
16
  MessagesOf = {
16
17
  # courier/module.esmtp/esmtpclient.c:526| hard_error(del, ctf, "No such domain.");
17
- 'hostunknown' => ['No such domain.'],
18
+ Sisimai::Eb::ReHOST => ['No such domain.'],
18
19
  # courier/module.esmtp/esmtpclient.c:531| hard_error(del, ctf,
19
20
  # courier/module.esmtp/esmtpclient.c:532| "This domain's DNS violates RFC 1035.");
20
- 'systemerror' => ["This domain's DNS violates RFC 1035."],
21
+ Sisimai::Eb::RePROC => ["This domain's DNS violates RFC 1035."],
21
22
  # courier/module.esmtp/esmtpclient.c:535| soft_error(del, ctf, "DNS lookup failed.");
22
- 'networkerror' => ['DNS lookup failed.'],
23
+ Sisimai::Eb::ReINET => ['DNS lookup failed.'],
23
24
  }.freeze
24
25
 
25
26
  # @abstract Decodes the bounce message from Courier MTA
@@ -3,13 +3,14 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module Domino
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
 
8
9
  Indicators = Sisimai::Lhost.INDICATORS
9
10
  Boundaries = ['Content-Type: message/rfc822'].freeze
10
11
  StartingOf = {message: ['Your message']}.freeze
11
12
  MessagesOf = {
12
- "userunknown" => [
13
+ Sisimai::Eb::ReUSER => [
13
14
  "not listed in Domino Directory",
14
15
  "not listed in public Name & Address Book",
15
16
  "non répertorié dans l'annuaire Domino",
@@ -3,6 +3,7 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module EinsUndEins
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
 
8
9
  Indicators = Sisimai::Lhost.INDICATORS
@@ -90,8 +91,8 @@ module Sisimai::Lhost
90
91
  p2 = e['diagnosis'].index(' reason:')
91
92
 
92
93
  e['rhost'] = e['diagnosis'][p1 + 6, p2 - p1 - 6]
93
- e['command'] = 'DATA' if e['diagnosis'].include?('for TEXT command')
94
- e['spec'] = 'SMTP' if e['diagnosis'].include?('SMTP error')
94
+ e['command'] = Sisimai::Eb::CeDATA if e['diagnosis'].include?('for TEXT command')
95
+ e['spec'] = 'SMTP' if e['diagnosis'].include?('SMTP error')
95
96
  e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
96
97
  else
97
98
  # For the following reason:
@@ -4,6 +4,7 @@ module Sisimai::Lhost
4
4
  # Methods in the module are called from only Sisimai::Message.
5
5
  module Exchange2003
6
6
  class << self
7
+ require 'sisimai/eb'
7
8
  require 'sisimai/lhost'
8
9
 
9
10
  Indicators = Sisimai::Lhost.INDICATORS
@@ -13,29 +14,29 @@ module Sisimai::Lhost
13
14
  error: ['did not reach the following recipient(s):'],
14
15
  }.freeze
15
16
  ErrorCodes = {
16
- 'onhold' => [
17
+ Sisimai::Eb::Re___1 => [
17
18
  '000B099C', # Host Unknown, Message exceeds size limit, ...
18
19
  '000B09AA', # Unable to relay for, Message exceeds size limit,...
19
20
  '000B09B6', # Error messages by remote MTA
20
21
  ],
21
- 'userunknown' => [
22
+ Sisimai::Eb::ReUSER => [
22
23
  '000C05A6', # Unknown Recipient,
23
24
  ],
24
- 'systemerror' => [
25
+ Sisimai::Eb::RePROC => [
25
26
  '00010256', # Too many recipients.
26
27
  '000D06B5', # No proxy for recipient (non-smtp mail?)
27
28
  ],
28
- 'networkerror' => [
29
+ Sisimai::Eb::ReINET => [
29
30
  '00120270', # Too Many Hops
30
31
  ],
31
- 'contenterror' => [
32
+ Sisimai::Eb::ReBODY => [
32
33
  '00050311', # Conversion to Internet format failed
33
34
  '000502CC', # Conversion to Internet format failed
34
35
  ],
35
- 'securityerror' => [
36
+ Sisimai::Eb::ReSAFE => [
36
37
  '000B0981', # 502 Server does not support AUTH
37
38
  ],
38
- 'filtered' => [
39
+ Sisimai::Eb::ReFILT => [
39
40
  '000C0595', # Ambiguous Recipient
40
41
  ],
41
42
  }.freeze
@@ -4,6 +4,7 @@ module Sisimai::Lhost
4
4
  # Methods in the module are called from only Sisimai::Message.
5
5
  module Exchange2007
6
6
  class << self
7
+ require 'sisimai/eb'
7
8
  require 'sisimai/lhost'
8
9
 
9
10
  Indicators = Sisimai::Lhost.INDICATORS
@@ -32,19 +33,19 @@ module Sisimai::Lhost
32
33
  ]
33
34
  }.freeze
34
35
  NDRSubject = {
35
- "SMTPSEND.DNS.NonExistentDomain" => "hostunknown", # 554 5.4.4 SMTPSEND.DNS.NonExistentDomain
36
- "SMTPSEND.DNS.MxLoopback" => "networkerror", # 554 5.4.4 SMTPSEND.DNS.MxLoopback
37
- "RESOLVER.ADR.BadPrimary" => "systemerror", # 550 5.2.0 RESOLVER.ADR.BadPrimary
38
- "RESOLVER.ADR.RecipNotFound" => "userunknown", # 550 5.1.1 RESOLVER.ADR.RecipNotFound
39
- "RESOLVER.ADR.RecipientNotFound" => "userunknown", # 550 5.1.1 RESOLVER.ADR.RecipientNotFound
40
- "RESOLVER.ADR.ExRecipNotFound" => "userunknown", # 550 5.1.1 RESOLVER.ADR.ExRecipNotFound
41
- "RESOLVER.ADR.RecipLimit" => "ratelimited", # 550 5.5.3 RESOLVER.ADR.RecipLimit
42
- "RESOLVER.ADR.InvalidInSmtp" => "systemerror", # 550 5.1.0 RESOLVER.ADR.InvalidInSmtp
43
- "RESOLVER.ADR.Ambiguous" => "systemerror", # 550 5.1.4 RESOLVER.ADR.Ambiguous, 420 4.2.0 RESOLVER.ADR.Ambiguous
44
- "RESOLVER.RST.AuthRequired" => "securityerror", # 550 5.7.1 RESOLVER.RST.AuthRequired
45
- "RESOLVER.RST.NotAuthorized" => "rejected", # 550 5.7.1 RESOLVER.RST.NotAuthorized
46
- "RESOLVER.RST.RecipSizeLimit" => "emailtoolarge", # 550 5.2.3 RESOLVER.RST.RecipSizeLimit
47
- "QUEUE.Expired" => "expired", # 550 4.4.7 QUEUE.Expired
36
+ "SMTPSEND.DNS.NonExistentDomain" => Sisimai::Eb::ReHOST, # 554 5.4.4 SMTPSEND.DNS.NonExistentDomain
37
+ "SMTPSEND.DNS.MxLoopback" => Sisimai::Eb::ReINET, # 554 5.4.4 SMTPSEND.DNS.MxLoopback
38
+ "RESOLVER.ADR.BadPrimary" => Sisimai::Eb::RePROC, # 550 5.2.0 RESOLVER.ADR.BadPrimary
39
+ "RESOLVER.ADR.RecipNotFound" => Sisimai::Eb::ReUSER, # 550 5.1.1 RESOLVER.ADR.RecipNotFound
40
+ "RESOLVER.ADR.RecipientNotFound" => Sisimai::Eb::ReUSER, # 550 5.1.1 RESOLVER.ADR.RecipientNotFound
41
+ "RESOLVER.ADR.ExRecipNotFound" => Sisimai::Eb::ReUSER, # 550 5.1.1 RESOLVER.ADR.ExRecipNotFound
42
+ "RESOLVER.ADR.RecipLimit" => Sisimai::Eb::ReRATE, # 550 5.5.3 RESOLVER.ADR.RecipLimit
43
+ "RESOLVER.ADR.InvalidInSmtp" => Sisimai::Eb::RePROC, # 550 5.1.0 RESOLVER.ADR.InvalidInSmtp
44
+ "RESOLVER.ADR.Ambiguous" => Sisimai::Eb::RePROC, # 550 5.1.4 RESOLVER.ADR.Ambiguous, 420 4.2.0 RESOLVER.ADR.Ambiguous
45
+ "RESOLVER.RST.AuthRequired" => Sisimai::Eb::ReSAFE, # 550 5.7.1 RESOLVER.RST.AuthRequired
46
+ "RESOLVER.RST.NotAuthorized" => Sisimai::Eb::ReFROM, # 550 5.7.1 RESOLVER.RST.NotAuthorized
47
+ "RESOLVER.RST.RecipSizeLimit" => Sisimai::Eb::ReSIZE, # 550 5.2.3 RESOLVER.RST.RecipSizeLimit
48
+ "QUEUE.Expired" => Sisimai::Eb::ReTIME, # 550 4.4.7 QUEUE.Expired
48
49
  }.freeze
49
50
  MailSender = ["postmaster@outlook.com", ".onmicrosoft.com"].freeze
50
51
  EmailTitle = [