sisimai 5.0.3-java → 5.2.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 (258) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codecovio.yml +3 -1
  3. data/.github/workflows/rake-test.yml +7 -3
  4. data/ChangeLog.md +136 -0
  5. data/Makefile +4 -2
  6. data/README-JA.md +32 -22
  7. data/README.md +31 -21
  8. data/lib/sisimai/arf.rb +124 -213
  9. data/lib/sisimai/fact/json.rb +2 -2
  10. data/lib/sisimai/fact/yaml.rb +2 -2
  11. data/lib/sisimai/fact.rb +208 -173
  12. data/lib/sisimai/lda.rb +98 -0
  13. data/lib/sisimai/lhost/activehunter.rb +5 -4
  14. data/lib/sisimai/lhost/amazonses.rb +189 -305
  15. data/lib/sisimai/lhost/apachejames.rb +52 -55
  16. data/lib/sisimai/lhost/biglobe.rb +5 -6
  17. data/lib/sisimai/lhost/courier.rb +14 -12
  18. data/lib/sisimai/lhost/domino.rb +29 -29
  19. data/lib/sisimai/lhost/dragonfly.rb +113 -0
  20. data/lib/sisimai/lhost/einsundeins.rb +7 -8
  21. data/lib/sisimai/lhost/exchange2003.rb +10 -11
  22. data/lib/sisimai/lhost/exchange2007.rb +115 -104
  23. data/lib/sisimai/lhost/exim.rb +236 -246
  24. data/lib/sisimai/lhost/ezweb.rb +47 -55
  25. data/lib/sisimai/lhost/fml.rb +6 -7
  26. data/lib/sisimai/lhost/gmail.rb +36 -32
  27. data/lib/sisimai/lhost/gmx.rb +8 -20
  28. data/lib/sisimai/lhost/googlegroups.rb +13 -12
  29. data/lib/sisimai/lhost/googleworkspace.rb +94 -0
  30. data/lib/sisimai/lhost/imailserver.rb +11 -19
  31. data/lib/sisimai/lhost/interscanmss.rb +6 -5
  32. data/lib/sisimai/lhost/kddi.rb +7 -8
  33. data/lib/sisimai/lhost/mailfoundry.rb +6 -9
  34. data/lib/sisimai/lhost/mailmarshalsmtp.rb +6 -6
  35. data/lib/sisimai/lhost/messagingserver.rb +19 -17
  36. data/lib/sisimai/lhost/mfilter.rb +8 -7
  37. data/lib/sisimai/lhost/notes.rb +6 -8
  38. data/lib/sisimai/lhost/opensmtpd.rb +11 -9
  39. data/lib/sisimai/lhost/postfix.rb +29 -31
  40. data/lib/sisimai/lhost/qmail.rb +136 -112
  41. data/lib/sisimai/lhost/sendmail.rb +23 -22
  42. data/lib/sisimai/lhost/v5sendmail.rb +93 -64
  43. data/lib/sisimai/lhost/verizon.rb +6 -6
  44. data/lib/sisimai/lhost/x1.rb +4 -4
  45. data/lib/sisimai/lhost/x2.rb +4 -5
  46. data/lib/sisimai/lhost/x3.rb +5 -5
  47. data/lib/sisimai/lhost/x6.rb +4 -4
  48. data/lib/sisimai/lhost/zoho.rb +6 -6
  49. data/lib/sisimai/lhost.rb +21 -24
  50. data/lib/sisimai/mail/maildir.rb +1 -1
  51. data/lib/sisimai/mail/stdin.rb +1 -1
  52. data/lib/sisimai/message.rb +100 -153
  53. data/lib/sisimai/order.rb +22 -77
  54. data/lib/sisimai/reason/authfailure.rb +1 -4
  55. data/lib/sisimai/reason/badreputation.rb +3 -3
  56. data/lib/sisimai/reason/blocked.rb +7 -10
  57. data/lib/sisimai/reason/contenterror.rb +7 -1
  58. data/lib/sisimai/reason/exceedlimit.rb +1 -4
  59. data/lib/sisimai/reason/failedstarttls.rb +42 -0
  60. data/lib/sisimai/reason/filtered.rb +5 -4
  61. data/lib/sisimai/reason/hasmoved.rb +1 -2
  62. data/lib/sisimai/reason/hostunknown.rb +3 -3
  63. data/lib/sisimai/reason/mailboxfull.rb +2 -4
  64. data/lib/sisimai/reason/mailererror.rb +1 -2
  65. data/lib/sisimai/reason/mesgtoobig.rb +2 -4
  66. data/lib/sisimai/reason/norelaying.rb +3 -3
  67. data/lib/sisimai/reason/notaccept.rb +2 -3
  68. data/lib/sisimai/reason/notcompliantrfc.rb +10 -4
  69. data/lib/sisimai/reason/rejected.rb +2 -1
  70. data/lib/sisimai/reason/requireptr.rb +2 -2
  71. data/lib/sisimai/reason/securityerror.rb +1 -3
  72. data/lib/sisimai/reason/spamdetected.rb +6 -8
  73. data/lib/sisimai/reason/speeding.rb +1 -2
  74. data/lib/sisimai/reason/suppressed.rb +36 -0
  75. data/lib/sisimai/reason/suspend.rb +1 -3
  76. data/lib/sisimai/reason/systemerror.rb +5 -0
  77. data/lib/sisimai/reason/toomanyconn.rb +1 -2
  78. data/lib/sisimai/reason/userunknown.rb +1 -1
  79. data/lib/sisimai/reason/virusdetected.rb +5 -6
  80. data/lib/sisimai/reason.rb +82 -78
  81. data/lib/sisimai/rfc1123.rb +152 -0
  82. data/lib/sisimai/rfc1894.rb +102 -62
  83. data/lib/sisimai/rfc2045.rb +2 -1
  84. data/lib/sisimai/rfc3464/thirdparty.rb +102 -0
  85. data/lib/sisimai/rfc3464.rb +224 -345
  86. data/lib/sisimai/rfc3834.rb +3 -3
  87. data/lib/sisimai/rfc5322.rb +7 -17
  88. data/lib/sisimai/rfc791.rb +69 -0
  89. data/lib/sisimai/rhost/aol.rb +36 -0
  90. data/lib/sisimai/rhost/apple.rb +95 -0
  91. data/lib/sisimai/rhost/cox.rb +84 -34
  92. data/lib/sisimai/rhost/facebook.rb +100 -0
  93. data/lib/sisimai/rhost/franceptt.rb +87 -83
  94. data/lib/sisimai/rhost/godaddy.rb +208 -45
  95. data/lib/sisimai/rhost/google.rb +22 -22
  96. data/lib/sisimai/rhost/gsuite.rb +42 -0
  97. data/lib/sisimai/rhost/iua.rb +5 -5
  98. data/lib/sisimai/rhost/kddi.rb +9 -7
  99. data/lib/sisimai/rhost/messagelabs.rb +37 -0
  100. data/lib/sisimai/rhost/microsoft.rb +60 -54
  101. data/lib/sisimai/rhost/mimecast.rb +44 -31
  102. data/lib/sisimai/rhost/nttdocomo.rb +5 -4
  103. data/lib/sisimai/rhost/outlook.rb +36 -0
  104. data/lib/sisimai/rhost/spectrum.rb +102 -41
  105. data/lib/sisimai/rhost/tencent.rb +48 -26
  106. data/lib/sisimai/rhost/yahooinc.rb +111 -0
  107. data/lib/sisimai/rhost.rb +65 -42
  108. data/lib/sisimai/smtp/command.rb +31 -21
  109. data/lib/sisimai/smtp/failure.rb +103 -0
  110. data/lib/sisimai/smtp/reply.rb +29 -24
  111. data/lib/sisimai/smtp/status.rb +36 -19
  112. data/lib/sisimai/smtp/transcript.rb +18 -18
  113. data/lib/sisimai/string.rb +0 -46
  114. data/lib/sisimai/version.rb +1 -1
  115. data/lib/sisimai.rb +0 -6
  116. data/set-of-emails/maildir/bsd/lhost-dragonfly-01.eml +36 -0
  117. data/set-of-emails/maildir/bsd/lhost-dragonfly-02.eml +32 -0
  118. data/set-of-emails/maildir/bsd/lhost-dragonfly-03.eml +32 -0
  119. data/set-of-emails/maildir/bsd/lhost-dragonfly-04.eml +31 -0
  120. data/set-of-emails/maildir/bsd/lhost-dragonfly-05.eml +32 -0
  121. data/set-of-emails/maildir/bsd/lhost-dragonfly-06.eml +32 -0
  122. data/set-of-emails/maildir/bsd/lhost-dragonfly-07.eml +32 -0
  123. data/set-of-emails/maildir/bsd/lhost-dragonfly-08.eml +32 -0
  124. data/set-of-emails/maildir/bsd/lhost-dragonfly-09.eml +32 -0
  125. data/set-of-emails/maildir/bsd/lhost-dragonfly-10.eml +32 -0
  126. data/set-of-emails/maildir/bsd/lhost-dragonfly-11.eml +32 -0
  127. data/set-of-emails/maildir/bsd/lhost-dragonfly-12.eml +32 -0
  128. data/set-of-emails/maildir/bsd/lhost-dragonfly-13.eml +32 -0
  129. data/set-of-emails/maildir/bsd/lhost-dragonfly-14.eml +32 -0
  130. data/set-of-emails/maildir/bsd/lhost-dragonfly-15.eml +32 -0
  131. data/set-of-emails/maildir/bsd/lhost-dragonfly-16.eml +32 -0
  132. data/set-of-emails/maildir/bsd/lhost-dragonfly-17.eml +32 -0
  133. data/set-of-emails/maildir/bsd/lhost-dragonfly-18.eml +32 -0
  134. data/set-of-emails/maildir/bsd/lhost-dragonfly-19.eml +32 -0
  135. data/set-of-emails/maildir/bsd/lhost-dragonfly-20.eml +32 -0
  136. data/set-of-emails/maildir/bsd/lhost-dragonfly-21.eml +33 -0
  137. data/set-of-emails/maildir/bsd/lhost-dragonfly-22.eml +32 -0
  138. data/set-of-emails/maildir/bsd/lhost-dragonfly-23.eml +32 -0
  139. data/set-of-emails/maildir/bsd/lhost-dragonfly-24.eml +32 -0
  140. data/set-of-emails/maildir/bsd/lhost-dragonfly-25.eml +33 -0
  141. data/set-of-emails/maildir/bsd/lhost-dragonfly-26.eml +33 -0
  142. data/set-of-emails/maildir/bsd/lhost-dragonfly-27.eml +47 -0
  143. data/set-of-emails/maildir/bsd/lhost-dragonfly-28.eml +47 -0
  144. data/set-of-emails/maildir/bsd/lhost-dragonfly-29.eml +32 -0
  145. data/set-of-emails/maildir/bsd/lhost-dragonfly-30.eml +32 -0
  146. data/set-of-emails/maildir/bsd/lhost-opensmtpd-10.eml +58 -0
  147. data/set-of-emails/maildir/bsd/lhost-opensmtpd-11.eml +58 -0
  148. data/set-of-emails/maildir/bsd/lhost-opensmtpd-12.eml +62 -0
  149. data/set-of-emails/maildir/bsd/lhost-opensmtpd-13.eml +62 -0
  150. data/set-of-emails/maildir/bsd/lhost-opensmtpd-14.eml +58 -0
  151. data/set-of-emails/maildir/bsd/lhost-opensmtpd-15.eml +63 -0
  152. data/set-of-emails/maildir/bsd/lhost-opensmtpd-16.eml +62 -0
  153. data/set-of-emails/maildir/bsd/lhost-opensmtpd-17.eml +63 -0
  154. data/set-of-emails/maildir/bsd/lhost-postfix-30.eml +81 -81
  155. data/set-of-emails/maildir/bsd/lhost-qmail-11.eml +29 -0
  156. data/set-of-emails/maildir/bsd/lhost-qmail-12.eml +29 -0
  157. data/set-of-emails/maildir/bsd/lhost-qmail-13.eml +29 -0
  158. data/set-of-emails/maildir/bsd/lhost-qmail-14.eml +34 -0
  159. data/set-of-emails/maildir/bsd/lhost-qmail-15.eml +30 -0
  160. data/set-of-emails/maildir/bsd/lhost-qmail-16.eml +31 -0
  161. data/set-of-emails/maildir/bsd/lhost-qmail-17.eml +38 -0
  162. data/set-of-emails/maildir/bsd/lhost-qmail-18.eml +31 -0
  163. data/set-of-emails/maildir/bsd/lhost-qmail-19.eml +31 -0
  164. data/set-of-emails/maildir/bsd/lhost-qmail-20.eml +46 -0
  165. data/set-of-emails/maildir/bsd/lhost-qmail-21.eml +41 -0
  166. data/set-of-emails/maildir/bsd/lhost-qmail-22.eml +42 -0
  167. data/set-of-emails/maildir/bsd/lhost-qmail-23.eml +43 -0
  168. data/set-of-emails/maildir/bsd/lhost-qmail-24.eml +43 -0
  169. data/set-of-emails/maildir/bsd/lhost-qmail-25.eml +54 -0
  170. data/set-of-emails/maildir/bsd/{lhost-aol-03.eml → rhost-aol-03.eml} +1264 -1264
  171. data/set-of-emails/maildir/bsd/{lhost-aol-04.eml → rhost-aol-04.eml} +1260 -1260
  172. data/set-of-emails/maildir/bsd/{lhost-aol-05.eml → rhost-aol-05.eml} +105 -105
  173. data/set-of-emails/maildir/bsd/{lhost-aol-06.eml → rhost-aol-06.eml} +105 -105
  174. data/set-of-emails/maildir/bsd/rhost-apple-01.eml +79 -0
  175. data/set-of-emails/maildir/bsd/rhost-apple-02.eml +81 -0
  176. data/set-of-emails/maildir/bsd/rhost-apple-03.eml +75 -0
  177. data/set-of-emails/maildir/bsd/rhost-apple-04.eml +74 -0
  178. data/set-of-emails/maildir/bsd/rhost-gsuite-01.eml +189 -0
  179. data/set-of-emails/maildir/bsd/rhost-gsuite-02.eml +180 -0
  180. data/set-of-emails/maildir/bsd/rhost-gsuite-03.eml +251 -0
  181. data/set-of-emails/maildir/bsd/rhost-gsuite-04.eml +211 -0
  182. data/set-of-emails/maildir/bsd/rhost-gsuite-05.eml +226 -0
  183. data/set-of-emails/maildir/bsd/rhost-gsuite-06.eml +257 -0
  184. data/set-of-emails/maildir/bsd/rhost-gsuite-07.eml +289 -0
  185. data/set-of-emails/maildir/bsd/rhost-gsuite-08.eml +231 -0
  186. data/set-of-emails/maildir/bsd/rhost-gsuite-09.eml +231 -0
  187. data/set-of-emails/maildir/bsd/rhost-gsuite-10.eml +254 -0
  188. data/set-of-emails/maildir/bsd/rhost-gsuite-11.eml +228 -0
  189. data/set-of-emails/maildir/bsd/rhost-gsuite-12.eml +271 -0
  190. data/set-of-emails/maildir/bsd/rhost-gsuite-13.eml +261 -0
  191. data/set-of-emails/maildir/bsd/rhost-gsuite-14.eml +273 -0
  192. data/set-of-emails/maildir/bsd/rhost-gsuite-15.eml +229 -0
  193. data/set-of-emails/maildir/bsd/{lhost-messagelabs-01.eml → rhost-messagelabs-01.eml} +93 -93
  194. data/set-of-emails/maildir/bsd/rhost-outlook-01.eml +72 -0
  195. data/set-of-emails/maildir/bsd/rhost-outlook-02.eml +72 -0
  196. data/set-of-emails/maildir/bsd/rhost-outlook-03.eml +72 -0
  197. data/set-of-emails/maildir/bsd/rhost-outlook-04.eml +79 -0
  198. data/set-of-emails/maildir/bsd/rhost-outlook-06.eml +75 -0
  199. data/set-of-emails/maildir/bsd/rhost-outlook-07.eml +70 -0
  200. data/set-of-emails/maildir/bsd/rhost-outlook-08.eml +70 -0
  201. data/set-of-emails/maildir/bsd/rhost-outlook-09.eml +56 -0
  202. data/set-of-emails/maildir/bsd/rhost-yahooinc-01.eml +80 -0
  203. data/set-of-emails/maildir/bsd/rhost-yahooinc-02.eml +83 -0
  204. data/set-of-emails/maildir/bsd/rhost-yahooinc-03.eml +125 -0
  205. data/set-of-emails/maildir/tmp/arf-22.eml +49 -0
  206. data/set-of-emails/maildir/tmp/arf-23.eml +49 -0
  207. data/set-of-emails/maildir/tmp/arf-24.eml +50 -0
  208. data/set-of-emails/maildir/tmp/lhost-exim-07.eml +28 -0
  209. metadata +136 -56
  210. data/lib/sisimai/lhost/amavis.rb +0 -163
  211. data/lib/sisimai/lhost/amazonworkmail.rb +0 -127
  212. data/lib/sisimai/lhost/aol.rb +0 -125
  213. data/lib/sisimai/lhost/barracuda.rb +0 -92
  214. data/lib/sisimai/lhost/bigfoot.rb +0 -125
  215. data/lib/sisimai/lhost/facebook.rb +0 -188
  216. data/lib/sisimai/lhost/gsuite.rb +0 -194
  217. data/lib/sisimai/lhost/mailru.rb +0 -214
  218. data/lib/sisimai/lhost/mcafee.rb +0 -109
  219. data/lib/sisimai/lhost/messagelabs.rb +0 -119
  220. data/lib/sisimai/lhost/mxlogic.rb +0 -198
  221. data/lib/sisimai/lhost/office365.rb +0 -252
  222. data/lib/sisimai/lhost/outlook.rb +0 -129
  223. data/lib/sisimai/lhost/powermta.rb +0 -118
  224. data/lib/sisimai/lhost/receivingses.rb +0 -126
  225. data/lib/sisimai/lhost/sendgrid.rb +0 -150
  226. data/lib/sisimai/lhost/surfcontrol.rb +0 -105
  227. data/lib/sisimai/lhost/x4.rb +0 -269
  228. data/lib/sisimai/lhost/x5.rb +0 -112
  229. data/lib/sisimai/lhost/yahoo.rb +0 -102
  230. data/lib/sisimai/lhost/yandex.rb +0 -118
  231. data/lib/sisimai/mda.rb +0 -121
  232. data/lib/sisimai/smtp/error.rb +0 -119
  233. /data/set-of-emails/maildir/bsd/{lhost-googlegroups-15.eml → lhost-googleworkspace-01.eml} +0 -0
  234. /data/set-of-emails/maildir/bsd/{lhost-x4-08.eml → lhost-x2-06.eml} +0 -0
  235. /data/set-of-emails/maildir/bsd/{lhost-gsuite-01.eml → rfc3464-51.eml} +0 -0
  236. /data/set-of-emails/maildir/bsd/{lhost-gsuite-03.eml → rfc3464-52.eml} +0 -0
  237. /data/set-of-emails/maildir/bsd/{lhost-gsuite-04.eml → rfc3464-53.eml} +0 -0
  238. /data/set-of-emails/maildir/bsd/{lhost-gsuite-05.eml → rfc3464-54.eml} +0 -0
  239. /data/set-of-emails/maildir/bsd/{lhost-gsuite-06.eml → rfc3464-55.eml} +0 -0
  240. /data/set-of-emails/maildir/bsd/{lhost-gsuite-07.eml → rfc3464-56.eml} +0 -0
  241. /data/set-of-emails/maildir/bsd/{lhost-gsuite-08.eml → rfc3464-57.eml} +0 -0
  242. /data/set-of-emails/maildir/bsd/{lhost-gsuite-09.eml → rfc3464-58.eml} +0 -0
  243. /data/set-of-emails/maildir/bsd/{lhost-gsuite-10.eml → rfc3464-59.eml} +0 -0
  244. /data/set-of-emails/maildir/bsd/{lhost-gsuite-11.eml → rfc3464-60.eml} +0 -0
  245. /data/set-of-emails/maildir/bsd/{lhost-gsuite-12.eml → rfc3464-61.eml} +0 -0
  246. /data/set-of-emails/maildir/bsd/{lhost-gsuite-13.eml → rfc3464-62.eml} +0 -0
  247. /data/set-of-emails/maildir/bsd/{lhost-gsuite-14.eml → rfc3464-63.eml} +0 -0
  248. /data/set-of-emails/maildir/bsd/{lhost-gsuite-15.eml → rfc3464-64.eml} +0 -0
  249. /data/set-of-emails/maildir/bsd/{lhost-gsuite-02.eml → rfc3464-65.eml} +0 -0
  250. /data/set-of-emails/maildir/bsd/{lhost-aol-01.eml → rhost-aol-01.eml} +0 -0
  251. /data/set-of-emails/maildir/bsd/{lhost-aol-02.eml → rhost-aol-02.eml} +0 -0
  252. /data/set-of-emails/maildir/bsd/{lhost-facebook-03.eml → rhost-facebook-03.eml} +0 -0
  253. /data/set-of-emails/maildir/bsd/{lhost-facebook-04.eml → rhost-facebook-04.eml} +0 -0
  254. /data/set-of-emails/maildir/bsd/{lhost-messagelabs-02.eml → rhost-messagelabs-02.eml} +0 -0
  255. /data/set-of-emails/maildir/bsd/{lhost-messagelabs-03.eml → rhost-messagelabs-03.eml} +0 -0
  256. /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-37.eml +0 -0
  257. /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-38.eml +0 -0
  258. /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-39.eml +0 -0
@@ -1,49 +1,51 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::ApacheJames parses a bounce email which created by ApacheJames. Methods in the
3
- # module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::ApacheJames decodes a bounce email which created by ApacheJames https://james.apache.org/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module ApacheJames
5
5
  class << self
6
6
  require 'sisimai/lhost'
7
7
 
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['Content-Type: message/rfc822'].freeze
9
+ Boundaries = ["Content-Type: message/rfc822"].freeze
10
10
  StartingOf = {
11
11
  # apache-james-2.3.2/src/java/org/apache/james/transport/mailets/
12
12
  # AbstractNotify.java|124: out.println("Error message below:");
13
13
  # AbstractNotify.java|128: out.println("Message details:");
14
- message: [''],
15
- error: ['Error message below:'],
14
+ message: ["Message details:"],
16
15
  }.freeze
17
16
 
18
- # Parse bounce messages from Apache James
17
+ # @abstract decodes the bounce message from Apache James
19
18
  # @param [Hash] mhead Message headers of a bounce email
20
19
  # @param [String] mbody Message body of a bounce email
21
20
  # @return [Hash] Bounce data list and message/rfc822 part
22
- # @return [Nil] it failed to parse or the arguments are missing
21
+ # @return [Nil] it failed to decode or the arguments are missing
23
22
  def inquire(mhead, mbody)
24
23
  match = 0
25
- match += 1 if mhead['subject'] == '[BOUNCE]'
26
- match += 1 if mhead['message-id'].to_s.include?('.JavaMail.')
27
- match += 1 if mhead['received'].any? { |a| a.include?('JAMES SMTP Server') }
24
+ match += 1 if mhead["subject"] == "[BOUNCE]"
25
+ match += 1 if mhead["message-id"].to_s.include?(".JavaMail.")
26
+ match += 1 if mhead["received"].any? { |a| a.include?("JAMES SMTP Server") }
28
27
  return nil unless match > 0
29
28
 
30
29
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
31
30
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
32
31
  bodyslices = emailparts[0].split("\n")
33
- readcursor = 0 # (Integer) Points the current cursor position
34
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
35
- issuedcode = '' # (String) Alternative diagnostic message
36
- subjecttxt = nil # (String) Alternative Subject text
37
- gotmessage = nil # (Boolean) Flag for error message
38
- v = nil
32
+ readcursor = 0 # Points the current cursor position
33
+ recipients = 0 # The number of 'Final-Recipient' header
34
+ alternates = ["", "", "", ""] # [Envelope-From, Header-From, Date, Subject]
35
+ v = dscontents[-1]
39
36
 
40
37
  while e = bodyslices.shift do
41
38
  # Read error messages and delivery status lines from the head of the email to the previous
42
39
  # line of the beginning of the original message.
43
-
44
40
  if readcursor == 0
45
41
  # Beginning of the bounce message or delivery status part
46
- readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
42
+ if e.start_with?(StartingOf[:message][0])
43
+ # Message details:
44
+ # Subject: Nyaaan
45
+ readcursor |= Indicators[:deliverystatus]
46
+ next
47
+ end
48
+ v["diagnosis"] << e << " " if e != ""
47
49
  next
48
50
  end
49
51
  next if (readcursor & Indicators[:deliverystatus]) == 0
@@ -58,58 +60,53 @@ module Sisimai::Lhost
58
60
  # To: kijitora@example.org
59
61
  # Size (in bytes): 1024
60
62
  # Number of lines: 64
61
- v = dscontents[-1]
62
-
63
- if e.start_with?(' RCPT TO: ')
63
+ if e.start_with?(" RCPT TO: ")
64
64
  # RCPT TO: kijitora@example.org
65
- if v['recipient']
65
+ if v["recipient"] != ""
66
66
  # There are multiple recipient addresses in the message body.
67
67
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
68
68
  v = dscontents[-1]
69
69
  end
70
- v['recipient'] = e[12, e.size]
70
+ v["recipient"] = e[12, e.size]
71
71
  recipients += 1
72
72
 
73
- elsif e.start_with?(' Sent date: ')
73
+ elsif e.start_with?(" Sent date: ")
74
74
  # Sent date: Thu Apr 29 01:20:50 JST 2015
75
- v['date'] = e[13, e.size]
75
+ v["date"] = e[13, e.size]
76
+ alternates[2] = v["date"]
76
77
 
77
- elsif e.start_with?(' Subject: ')
78
+ elsif e.start_with?(" Subject: ")
78
79
  # Subject: Nyaaan
79
- subjecttxt = e[11, e.size]
80
- else
81
- next if gotmessage
82
- if v['diagnosis']
83
- # Get an error message text
84
- if e.start_with?('Message details:')
85
- # Message details:
86
- # Subject: nyaan
87
- # ...
88
- gotmessage = true
89
- else
90
- # Append error message text like the followng:
91
- # Error message below:
92
- # 550 - Requested action not taken: no such user here
93
- v['diagnosis'] << ' ' << e
94
- end
95
- else
96
- # Error message below:
97
- # 550 - Requested action not taken: no such user here
98
- v['diagnosis'] = e if e == StartingOf[:error][0]
99
- unless gotmessage
100
- v['diagnosis'] ||= ''
101
- v['diagnosis'] << ' ' + e
102
- end
103
- end
80
+ alternates[3] = e[11, e.size]
81
+
82
+ elsif e.start_with?(" MAIL FROM: ")
83
+ # MAIL FROM: shironeko@example.jp
84
+ alternates[0] = e[13, e.size]
85
+
86
+ elsif e.start_with?(" From: ")
87
+ # From: Neko <shironeko@example.jp>
88
+ alternates[1] = e[8, e.size]
89
+
104
90
  end
105
91
  end
106
92
  return nil unless recipients > 0
107
93
 
108
- # Set the value of subjecttxt as a Subject if there is no original message in the bounce mail.
109
- emailparts[1] << ('Subject: ' << subjecttxt << "\n") unless emailparts[1].index("\nSubject:")
94
+ if emailparts[1].empty?
95
+ # The original message is empty
96
+ emailparts[1] << sprintf("From: %s\n", alternates[1]) if alternates[1] != ""
97
+ emailparts[1] << sprintf("Date: %s\n", alternates[2]) if alternates[2] != ""
98
+ end
99
+ if emailparts[1].include?("Return-Path: ") == false
100
+ # Set the envelope from address as a Return-Path: header
101
+ emailparts[1] << sprintf("Return-Path: <%s>\n", alternates[0]) if alternates[0] != ""
102
+ end
103
+ if emailparts[1].include?("\nSubject: ") == false
104
+ # Set the envelope from address as a Return-Path: header
105
+ emailparts[1] << sprintf("Subject: %s\n", alternates[3]) if alternates[3] != ""
106
+ end
110
107
 
111
- dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode) }
112
- return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
108
+ dscontents.each { |e| e["diagnosis"] = Sisimai::String.sweep(e["diagnosis"]) }
109
+ return { "ds" => dscontents, "rfc822" => emailparts[1] }
113
110
  end
114
111
  def description; return 'Java Apache Mail Enterprise Server'; end
115
112
  end
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Biglobe parses a bounce email which created by BIGLOBE. Methods in the module
3
- # are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Biglobe decodes a bounce email which created by BIGLOBE https://www.biglobe.ne.jp/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module Biglobe
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -16,11 +16,11 @@ module Sisimai::Lhost
16
16
  'mailboxfull' => ["The number of messages in recipient's mailbox exceeded the local limit."],
17
17
  }.freeze
18
18
 
19
- # Parse bounce messages from Biglobe
19
+ # @asbtract Decodes the bounce message from Biglobe
20
20
  # @param [Hash] mhead Message headers of a bounce email
21
21
  # @param [String] mbody Message body of a bounce email
22
22
  # @return [Hash] Bounce data list and message/rfc822 part
23
- # @return [Nil] it failed to parse or the arguments are missing
23
+ # @return [Nil] it failed to decode or the arguments are missing
24
24
  def inquire(mhead, mbody)
25
25
  return nil unless mhead['from'].include?('postmaster@')
26
26
  return nil unless %w[biglobe inacatv tmtv ttv].any? { |a| mhead['from'].include?('@' + a + '.ne.jp') }
@@ -63,7 +63,7 @@ module Sisimai::Lhost
63
63
  if e.include?('@') && e.include?(' ') == false
64
64
  # ----- The following addresses had delivery problems -----
65
65
  # ********@***.biglobe.ne.jp
66
- if v['recipient']
66
+ if v["recipient"] != ""
67
67
  # There are multiple recipient addresses in the message body.
68
68
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
69
69
  v = dscontents[-1]
@@ -74,7 +74,6 @@ module Sisimai::Lhost
74
74
  recipients += 1
75
75
  else
76
76
  next if e.include?('--')
77
- v['diagnosis'] ||= ''
78
77
  v['diagnosis'] << e + ' '
79
78
  end
80
79
  end
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Courier parses a bounce email which created by Courier MTA. Methods in the module
3
- # are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Courier decodes a bounce email which created by Courier MTA https://www.courier-mta.org/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module Courier
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -12,7 +12,6 @@ module Sisimai::Lhost
12
12
  # courier/module.dsn/dsn*.txt
13
13
  message: ['DELAYS IN DELIVERING YOUR MESSAGE', 'UNDELIVERABLE MAIL'],
14
14
  }.freeze
15
-
16
15
  MessagesOf = {
17
16
  # courier/module.esmtp/esmtpclient.c:526| hard_error(del, ctf, "No such domain.");
18
17
  'hostunknown' => ['No such domain.'],
@@ -23,11 +22,11 @@ module Sisimai::Lhost
23
22
  'networkerror' => ['DNS lookup failed.'],
24
23
  }.freeze
25
24
 
26
- # Parse bounce messages from Courier MTA
25
+ # @abstract Decodes the bounce message from Courier MTA
27
26
  # @param [Hash] mhead Message headers of a bounce email
28
27
  # @param [String] mbody Message body of a bounce email
29
28
  # @return [Hash] Bounce data list and message/rfc822 part
30
- # @return [Nil] it failed to parse or the arguments are missing
29
+ # @return [Nil] it failed to decode or the arguments are missing
31
30
  def inquire(mhead, mbody)
32
31
  match = 0
33
32
  match += 1 if mhead['from'].include?('Courier mail server at ')
@@ -39,8 +38,9 @@ module Sisimai::Lhost
39
38
  end
40
39
  return nil unless match > 0
41
40
 
42
- require 'sisimai/smtp/command'
41
+ require 'sisimai/rfc1123'
43
42
  require 'sisimai/rfc1894'
43
+ require 'sisimai/smtp/command'
44
44
  fieldtable = Sisimai::RFC1894.FIELDTABLE
45
45
  permessage = {} # (Hash) Store values of each Per-Message field
46
46
 
@@ -68,17 +68,18 @@ module Sisimai::Lhost
68
68
  next if (readcursor & Indicators[:deliverystatus]) == 0
69
69
  next if e.empty?
70
70
 
71
- if f = Sisimai::RFC1894.match(e)
71
+ f = Sisimai::RFC1894.match(e)
72
+ if f > 0
72
73
  # "e" matched with any field defined in RFC3464
73
74
  next unless o = Sisimai::RFC1894.field(e)
74
75
  v = dscontents[-1]
75
76
 
76
- if o[-1] == 'addr'
77
+ if o[3] == 'addr'
77
78
  # Final-Recipient: rfc822; kijitora@example.jp
78
79
  # X-Actual-Recipient: rfc822; kijitora@example.co.jp
79
80
  if o[0] == 'final-recipient'
80
81
  # Final-Recipient: rfc822; kijitora@example.jp
81
- if v['recipient']
82
+ if v["recipient"] != ""
82
83
  # There are multiple recipient addresses in the message body.
83
84
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
84
85
  v = dscontents[-1]
@@ -89,16 +90,17 @@ module Sisimai::Lhost
89
90
  # X-Actual-Recipient: rfc822; kijitora@example.co.jp
90
91
  v['alias'] = o[2]
91
92
  end
92
- elsif o[-1] == 'code'
93
+ elsif o[3] == 'code'
93
94
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
94
95
  v['spec'] = o[1]
95
96
  v['diagnosis'] = o[2]
96
97
  else
97
98
  # Other DSN fields defined in RFC3464
98
99
  next unless fieldtable[o[0]]
100
+ next if o[3] == "host" && Sisimai::RFC1123.is_internethost(o[2]) == false
99
101
  v[fieldtable[o[0]]] = o[2]
100
102
 
101
- next unless f
103
+ next unless f == 1
102
104
  permessage[fieldtable[o[0]]] = o[2]
103
105
  end
104
106
  else
@@ -126,7 +128,7 @@ module Sisimai::Lhost
126
128
  dscontents.each do |e|
127
129
  # Set default values if each value is empty.
128
130
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
129
- e['command'] ||= thecommand || ''
131
+ e['command'] = thecommand if e["command"].empty?
130
132
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
131
133
 
132
134
  MessagesOf.each_key do |r|
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Domino parses a bounce email which created by IBM Domino Server. Methods in the
3
- # module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Domino decodes a bounce email which created by HCL Domino https://www.hcl-software.com/domino.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module Domino
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -9,25 +9,26 @@ module Sisimai::Lhost
9
9
  Boundaries = ['Content-Type: message/rfc822'].freeze
10
10
  StartingOf = { message: ['Your message'] }.freeze
11
11
  MessagesOf = {
12
- 'userunknown' => [
13
- 'not listed in Domino Directory',
14
- 'not listed in public Name & Address Book',
12
+ "filtered" => ["Cannot route mail to user"],
13
+ "systemerror" => ["Several matches found in Domino Directory"],
14
+ "userunknown" => [
15
+ "not listed in Domino Directory",
16
+ "not listed in public Name & Address Book",
15
17
  "non répertorié dans l'annuaire Domino",
16
- 'no se encuentra en el Directorio de Domino',
17
- 'Domino ディレクトリには見つかりません',
18
+ "no se encuentra en el Directorio de Domino",
19
+ "Domino ディレクトリには見つかりません",
18
20
  ],
19
- 'filtered' => ['Cannot route mail to user'],
20
- 'systemerror' => ['Several matches found in Domino Directory'],
21
21
  }.freeze
22
22
 
23
- # Parse bounce messages from IBM Domino Server
23
+ # @abstract Decodes the bounce message from HCL Domino (formerly IBM Domino Server (formerly Lotus Domino))
24
24
  # @param [Hash] mhead Message headers of a bounce email
25
25
  # @param [String] mbody Message body of a bounce email
26
26
  # @return [Hash] Bounce data list and message/rfc822 part
27
- # @return [Nil] it failed to parse or the arguments are missing
27
+ # @return [Nil] it failed to decode or the arguments are missing
28
28
  def inquire(mhead, mbody)
29
29
  return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:', 'DELIVERY_FAILURE:')
30
30
 
31
+ require 'sisimai/rfc1123'
31
32
  require 'sisimai/rfc1894'
32
33
  fieldtable = Sisimai::RFC1894.FIELDTABLE
33
34
  permessage = {} # (Hash) Store values of each Per-Message field
@@ -68,12 +69,13 @@ module Sisimai::Lhost
68
69
 
69
70
  if e.start_with?('was not delivered to:')
70
71
  # was not delivered to:
71
- if v['recipient']
72
+ # kijitora@example.net
73
+ if v["recipient"] != ""
72
74
  # There are multiple recipient addresses in the message body.
73
75
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
74
76
  v = dscontents[-1]
75
77
  end
76
- v['recipient'] ||= e
78
+ v['recipient'] = e if v["recipient"].empty?
77
79
  recipients += 1
78
80
 
79
81
  elsif e.start_with?(' ') && e.include?('@') && e.index(' ', 3).nil?
@@ -83,9 +85,10 @@ module Sisimai::Lhost
83
85
 
84
86
  elsif e.start_with?('because:')
85
87
  # because:
88
+ # User some.name (kijitora@example.net) not listed in Domino Directory
86
89
  v['diagnosis'] = e
87
90
  else
88
- if v['diagnosis'].to_s == 'because:'
91
+ if v['diagnosis'] == "because:"
89
92
  # Error message, continued from the line "because:"
90
93
  v['diagnosis'] = e
91
94
 
@@ -93,28 +96,25 @@ module Sisimai::Lhost
93
96
  # Subject: Nyaa
94
97
  subjecttxt = e[11, e.size]
95
98
 
96
- elsif f = Sisimai::RFC1894.match(e)
97
- # There are some fields defined in RFC3464, try to match
98
- o = Sisimai::RFC1894.field(e) || next
99
- next if o[-1] == 'addr'
99
+ else
100
+ # Other fields defined in RFC3464
101
+ f = Sisimai::RFC1894.match(e); next if f < 1
102
+ o = Sisimai::RFC1894.field(e); next if o.nil?
103
+ next if o[3] == 'addr'
100
104
 
101
- if o[-1] == 'code'
105
+ if o[3] == 'code'
102
106
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
103
- v['spec'] = o[1] if v['spec'].to_s.empty?
104
- v['diagnosis'] = o[2] if v['diagnosis'].to_s.empty?
107
+ v['spec'] = o[1] if v['spec'].empty?
108
+ v['diagnosis'] = o[2] if v['diagnosis'].empty?
105
109
  else
106
110
  # Other DSN fields defined in RFC3464
107
111
  next unless fieldtable[o[0]]
112
+ next if o[3] == "host" && Sisimai::RFC1123.is_internethost(o[2]) == false
108
113
  v[fieldtable[o[0]]] = o[2]
109
114
 
110
- next unless f
115
+ next unless f == 1
111
116
  permessage[fieldtable[o[0]]] = o[2]
112
117
  end
113
- else
114
- if v['diagnosis'] && e.start_with?("\s", "\t")
115
- # The line is a continued line of "Diagnostic-Code:" field
116
- v['diagnosis'] += e.sub(/\A[\s\t]+/, '')
117
- end
118
118
  end
119
119
  end
120
120
  end
@@ -128,8 +128,8 @@ module Sisimai::Lhost
128
128
  MessagesOf.each_key do |r|
129
129
  # Check each regular expression of Domino error messages
130
130
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
131
- e['reason'] = r
132
- e['status'] ||= Sisimai::SMTP::Status.code(r.to_s, false) || ''
131
+ e['reason'] = r
132
+ e['status'] = Sisimai::SMTP::Status.code(r, false) if e["status"].empty?
133
133
  break
134
134
  end
135
135
  end
@@ -0,0 +1,113 @@
1
+ module Sisimai::Lhost
2
+ # Sisimai::Lhost::DragonFly decodes a bounce email which created by DMA: DragonFly Mail Agent
3
+ # https://www.dragonflybsd.org/handbook/mta/.
4
+ # Methods in the module are called from only Sisimai::Message.
5
+ module DragonFly
6
+ class << self
7
+ require 'sisimai/lhost'
8
+ require 'sisimai/address'
9
+ require 'sisimai/smtp/command'
10
+
11
+ Indicators = Sisimai::Lhost.INDICATORS
12
+ Boundaries = ['Original message follows.', 'Message headers follow'].freeze
13
+ StartingOf = {
14
+ # https://github.com/corecode/dma/blob/ffad280aa40c242aa9a2cb9ca5b1b6e8efedd17e/mail.c#L84
15
+ message: ['This is the DragonFly Mail Agent '],
16
+ }.freeze
17
+ MessagesOf = {
18
+ 'expired' => [
19
+ # https://github.com/corecode/dma/blob/master/dma.c#L370C1-L374C19
20
+ # dma.c:370| if (gettimeofday(&now, NULL) == 0 &&
21
+ # dma.c:371| (now.tv_sec - st.st_mtim.tv_sec > MAX_TIMEOUT)) {
22
+ # dma.c:372| snprintf(errmsg, sizeof(errmsg),
23
+ # dma.c:373| "Could not deliver for the last %d seconds. Giving up.",
24
+ # dma.c:374| MAX_TIMEOUT);
25
+ # dma.c:375| goto bounce;
26
+ # dma.c:376| }
27
+ 'Could not deliver for the last ',
28
+ ],
29
+ 'hostunknown' => [
30
+ # net.c:663| snprintf(errmsg, sizeof(errmsg), "DNS lookup failure: host %s not found", host);
31
+ 'DNS lookup failure: host ',
32
+ ],
33
+ }.freeze
34
+
35
+ # @abstract Decodes the bounce message from DMA: DragonFly Mail Agent
36
+ # @param [Hash] mhead Message headers of a bounce email
37
+ # @param [String] mbody Message body of a bounce email
38
+ # @return [Hash] Bounce data list and message/rfc822 part
39
+ # @return [Nil] it failed to decode or the arguments are missing
40
+ def inquire(mhead, mbody)
41
+ return nil unless mhead['subject'].start_with?('Mail delivery failed')
42
+ return nil unless mhead['received'].any? { |a| a.include?(' (DragonFly Mail Agent') }
43
+
44
+ dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
45
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
46
+ bodyslices = emailparts[0].split("\n")
47
+ readcursor = 0 # (Integer) Points the current cursor position
48
+ recipients = 0 # (Integer) The number of 'Final-Recipient' header
49
+ v = nil
50
+
51
+ while e = bodyslices.shift do
52
+ # Read error messages and delivery status lines from the head of the email to the previous
53
+ # line of the beginning of the original message.
54
+ if readcursor == 0
55
+ # Beginning of the bounce message or delivery status part
56
+ readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
57
+ next
58
+ end
59
+ next if (readcursor & Indicators[:deliverystatus]) == 0
60
+ next if e.empty?
61
+
62
+ # This is the DragonFly Mail Agent v0.13 at df.example.jp.
63
+ #
64
+ # There was an error delivering your mail to <kijitora@example.com>.
65
+ #
66
+ # email.example.jp [192.0.2.25] did not like our RCPT TO:
67
+ # 552 5.2.2 <kijitora@example.com>: Recipient address rejected: Mailbox full
68
+ #
69
+ # Original message follows.
70
+ v = dscontents[-1]
71
+
72
+ if e.start_with?('There was an error delivering your mail to <')
73
+ # email.example.jp [192.0.2.25] did not like our RCPT TO:
74
+ # 552 5.2.2 <kijitora@example.com>: Recipient address rejected: Mailbox full
75
+ if v["recipient"] != ""
76
+ # There are multiple recipient addresses in the message body.
77
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
78
+ v = dscontents[-1]
79
+ end
80
+ v['recipient'] = Sisimai::Address.find(e, false)[0][:address]
81
+ recipients += 1
82
+ else
83
+ # Pick the error message
84
+ v['diagnosis'] << ' ' << e
85
+
86
+ # Pick the remote hostname, and the SMTP command
87
+ # net.c:500| snprintf(errmsg, sizeof(errmsg), "%s [%s] did not like our %s:\n%s",
88
+ next unless e.include?(' did not like our ')
89
+ next if v['rhost'] != ""
90
+
91
+ p = e.split(' ', 3)
92
+ v['rhost'] = if p[0].include?('.') then p[0] else p[1] end
93
+ v['command'] = Sisimai::SMTP::Command.find(e)
94
+ end
95
+ end
96
+ return nil unless recipients > 0
97
+
98
+ dscontents.each do |e|
99
+ e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
100
+ MessagesOf.each_key do |r|
101
+ # Verify each regular expression of session errors
102
+ next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
103
+ e['reason'] = r
104
+ break
105
+ end
106
+ end
107
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
108
+ end
109
+ def description; return 'DragonFly'; end
110
+ end
111
+ end
112
+ end
113
+
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::EinsUndEins parses a bounce email which created by 1&1. Methods in the module are
3
- # called from only Sisimai::Message.
2
+ # Sisimai::Lhost::EinsUndEins decodes a bounce email which created by 1&1 https://www.1und1.de/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module EinsUndEins
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -13,11 +13,11 @@ module Sisimai::Lhost
13
13
  }.freeze
14
14
  MessagesOf = { 'mesgtoobig' => ['Mail size limit exceeded'] }.freeze
15
15
 
16
- # Parse bounce messages from 1&1
16
+ # @abstract Decode the bounce message from 1&1
17
17
  # @param [Hash] mhead Message headers of a bounce email
18
18
  # @param [String] mbody Message body of a bounce email
19
19
  # @return [Hash] Bounce data list and message/rfc822 part
20
- # @return [Nil] it failed to parse or the arguments are missing
20
+ # @return [Nil] it failed to decode or the arguments are missing
21
21
  def inquire(mhead, mbody)
22
22
  return nil unless mhead['from'].start_with?('"Mail Delivery System"')
23
23
  return nil unless mhead['subject'] == 'Mail delivery failed: returning message to sender'
@@ -54,7 +54,7 @@ module Sisimai::Lhost
54
54
  if cv = e.match(/\A\s*([^ ]+[@][^ ]+?)[:]?\z/)
55
55
  # general@example.eu OR
56
56
  # the line begin with 4 space characters, end with ":" like " neko@example.eu:"
57
- if v['recipient']
57
+ if v["recipient"] != ""
58
58
  # There are multiple recipient addresses in the message body.
59
59
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
60
60
  v = dscontents[-1]
@@ -82,9 +82,8 @@ module Sisimai::Lhost
82
82
 
83
83
  require 'sisimai/smtp/command'
84
84
  dscontents.each do |e|
85
- e['diagnosis'] ||= ''
86
- e['diagnosis'] = e['alterrors'] if e['diagnosis'].empty?
87
- e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
85
+ e['diagnosis'] = e['alterrors'] if e['diagnosis'].empty?
86
+ e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
88
87
 
89
88
  if Sisimai::String.aligned(e['diagnosis'], ['host: ', ' reason:'])
90
89
  # SMTP error from remote server for TEXT command,
@@ -1,5 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Exchange2003 parses a bounce email which created by Microsoft Exchange Server 2003.
2
+ # Sisimai::Lhost::Exchange2003 decodes a bounce email which created by Microsoft Exchange Server
3
+ # 2003 https://www.microsoft.com/microsoft-365/exchange/email.
3
4
  # Methods in the module are called from only Sisimai::Message.
4
5
  module Exchange2003
5
6
  class << self
@@ -39,11 +40,11 @@ module Sisimai::Lhost
39
40
  ],
40
41
  }.freeze
41
42
 
42
- # Parse bounce messages from Microsoft Exchange Server 2003
43
+ # @abstract Decodes the bounce message from Microsoft Exchange Server 2003
43
44
  # @param [Hash] mhead Message headers of a bounce email
44
45
  # @param [String] mbody Message body of a bounce email
45
46
  # @return [Hash] Bounce data list and message/rfc822 part
46
- # @return [Nil] it failed to parse or the arguments are missing
47
+ # @return [Nil] it failed to decode or the arguments are missing
47
48
  def inquire(mhead, mbody)
48
49
  match = 0
49
50
  tryto = []
@@ -125,7 +126,7 @@ module Sisimai::Lhost
125
126
  if Sisimai::String.aligned(e, ['@', ' on '])
126
127
  # kijitora@example.co.jp on Thu, 29 Apr 2007 16:51:51 -0500
127
128
  # kijitora@example.com on 4/29/99 9:19:59 AM
128
- if v['recipient']
129
+ if v["recipient"] != ""
129
130
  # There are multiple recipient addresses in the message body.
130
131
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
131
132
  v = dscontents[-1]
@@ -138,11 +139,10 @@ module Sisimai::Lhost
138
139
 
139
140
  elsif e.start_with?(' ') && e.include?('MSEXCH:')
140
141
  # MSEXCH:IMS:KIJITORA CAT:EXAMPLE:EXCHANGE 0 (000C05A6) Unknown Recipient
141
- v['diagnosis'] ||= ''
142
142
  v['diagnosis'] << e[e.index('MSEXCH:'), e.size]
143
143
  else
144
144
  next if v['msexch']
145
- if v['diagnosis'].to_s.start_with?('MSEXCH:')
145
+ if v['diagnosis'].start_with?('MSEXCH:')
146
146
  # Continued from MEEXCH in the previous line
147
147
  v['msexch'] = true
148
148
  v['diagnosis'] << ' ' << e
@@ -185,7 +185,7 @@ module Sisimai::Lhost
185
185
 
186
186
  dscontents.each do |e|
187
187
  e.delete('msexch')
188
- e['diagnosis'] ||= ''
188
+
189
189
  if e['diagnosis'].start_with?('MSEXCH:')
190
190
  # MSEXCH:IMS:KIJITORA CAT:EXAMPLE:EXCHANGE 0 (000C05A6) Unknown Recipient
191
191
  p1 = e['diagnosis'].index('(') || -1
@@ -197,16 +197,15 @@ module Sisimai::Lhost
197
197
  # Find captured code from the error code table
198
198
  next unless ErrorCodes[r].index(capturedcode)
199
199
  e['reason'] = r
200
- e['status'] = Sisimai::SMTP::Status.code(r.to_s) || ''
200
+ e['status'] = Sisimai::SMTP::Status.code(r) || ""
201
201
  break
202
202
  end
203
203
  e['diagnosis'] = errormessage
204
204
  end
205
205
 
206
- unless e['reason']
206
+ if e["reason"].empty?
207
207
  # Could not detect the reason from the value of "diagnosis".
208
- next unless e['alterrors']
209
- next if e['alterrors'].empty?
208
+ next if e["alterrors"].empty?
210
209
 
211
210
  # Copy alternative error message
212
211
  e['diagnosis'] = e['alterrors'] + ' ' + e['diagnosis']