sisimai 5.0.3 → 5.2.0

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,35 +1,35 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::EZweb parses a bounce email which created by au EZweb. Methods in the module are
3
- # called from only Sisimai::Message.
2
+ # Sisimai::Lhost::EZweb decodes a bounce email which created by au EZweb https://www.au.com/mobile/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module EZweb
5
5
  class << self
6
6
  require 'sisimai/lhost'
7
7
 
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['--------------------------------------------------', 'Content-Type: message/rfc822'].freeze
10
- MarkingsOf = { message: ['The user(s) ', 'Your message ', 'Each of the following', '<'] }.freeze
11
- ReFailures = {
9
+ Boundaries = ["--------------------------------------------------", "Content-Type: message/rfc822"].freeze
10
+ StartingOf = { message: ['The user(s) ', 'Your message ', 'Each of the following', '<'] }.freeze
11
+ Messagesof = {
12
12
  # notaccept: ['The following recipients did not receive this message:'],
13
+ 'expired' => [
14
+ # Your message was not delivered within 0 days and 1 hours.
15
+ # Remote host is not responding.
16
+ 'Your message was not delivered within ',
17
+ ],
13
18
  'mailboxfull' => ['The user(s) account is temporarily over quota'],
19
+ 'onhold' => ['Each of the following recipients was rejected by a remote mail server'],
14
20
  'suspend' => [
15
21
  # http://www.naruhodo-au.kddi.com/qa3429203.html
16
22
  # The recipient may be unpaid user...?
17
23
  'The user(s) account is disabled.',
18
24
  'The user(s) account is temporarily limited.',
19
25
  ],
20
- 'expired' => [
21
- # Your message was not delivered within 0 days and 1 hours.
22
- # Remote host is not responding.
23
- 'Your message was not delivered within ',
24
- ],
25
- 'onhold' => ['Each of the following recipients was rejected by a remote mail server'],
26
26
  }.freeze
27
27
 
28
- # Parse bounce messages from au EZweb
28
+ # @abstract Decodes the bounce message from au EZweb
29
29
  # @param [Hash] mhead Message headers of a bounce email
30
30
  # @param [String] mbody Message body of a bounce email
31
31
  # @return [Hash] Bounce data list and message/rfc822 part
32
- # @return [Nil] it failed to parse or the arguments are missing
32
+ # @return [Nil] it failed to decode or the arguments are missing
33
33
  def inquire(mhead, mbody)
34
34
  match = 0
35
35
  match += 1 if mhead['from'].include?('Postmaster@ezweb.ne.jp')
@@ -48,7 +48,7 @@ module Sisimai::Lhost
48
48
  bodyslices = emailparts[0].split("\n")
49
49
  readcursor = 0 # (Integer) Points the current cursor position
50
50
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
51
- rxmessages = []; ReFailures.each_value { |a| rxmessages << a }
51
+ substrings = []; Messagesof.each_value { |a| substrings << a }; substrings.flatten!
52
52
  v = nil
53
53
 
54
54
  while e = bodyslices.shift do
@@ -56,7 +56,7 @@ module Sisimai::Lhost
56
56
  # line of the beginning of the original message.
57
57
  if readcursor == 0
58
58
  # Beginning of the bounce message or delivery status part
59
- readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.include?(a) }
59
+ readcursor |= Indicators[:deliverystatus] if StartingOf[:message].any? { |a| e.include?(a) }
60
60
  end
61
61
  next if (readcursor & Indicators[:deliverystatus]) == 0
62
62
  next if e.empty?
@@ -79,81 +79,73 @@ module Sisimai::Lhost
79
79
  p1 = e.index('<') || -1
80
80
  p2 = e.index('>') || -1
81
81
 
82
- if v['recipient']
82
+ if v["recipient"] != ""
83
83
  # There are multiple recipient addresses in the message body.
84
84
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
85
85
  v = dscontents[-1]
86
86
  end
87
- v['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
87
+ v["recipient"] = Sisimai::Address.s3s4(e[p1, p2 - p1])
88
+ v["diagnosis"] << " " << e
88
89
  recipients += 1
89
90
 
90
- elsif f = Sisimai::RFC1894.match(e)
91
+ elsif Sisimai::RFC1894.match(e) > 0
91
92
  # "e" matched with any field defined in RFC3464
92
93
  next unless o = Sisimai::RFC1894.field(e)
93
94
  next unless fieldtable[o[0]]
94
95
  v[fieldtable[o[0]]] = o[2]
95
96
 
96
97
  else
97
- # The line does not begin with a DSN field defined in RFC3464
98
+ # Other error messages
98
99
  next if Sisimai::String.is_8bit(e)
99
- if e.include?('>>> ')
100
+ if e.include?(" >>> ")
100
101
  # >>> RCPT TO:<******@ezweb.ne.jp>
101
- v['command'] = Sisimai::SMTP::Command.find(e) || ''
102
+ v["command"] = Sisimai::SMTP::Command.find(e)
103
+ v["diagnosis"] << " " << e
104
+
105
+ elsif e.include?(" <<< ")
106
+ # <<< 550 ...
107
+ v["diagnosis"] << " " << e
108
+
102
109
  else
103
110
  # Check error message
104
- if rxmessages.any? { |messages| messages.any? { |message| e.include?(message) } }
111
+ isincluded = false
112
+ if substrings.any? { |a| e.include?(a) }
105
113
  # Check with regular expressions of each error
106
- v['diagnosis'] ||= ''
107
- v['diagnosis'] << ' ' << e
108
- else
109
- # >>> 550
110
- v['alterrors'] ||= ''
111
- v['alterrors'] << ' ' << e
114
+ v["diagnosis"] << " " << e
115
+ isincluded = true
112
116
  end
117
+ v["diagnosis"] << " " << e if isincluded
113
118
  end
114
119
  end
115
120
  end
116
121
  return nil unless recipients > 0
117
122
 
118
123
  dscontents.each do |e|
119
- unless e['alterrors'].to_s.empty?
120
- # Copy alternative error message
121
- e['diagnosis'] ||= e['alterrors']
122
- if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
123
- # Override the value of diagnostic code message
124
- e['diagnosis'] = e['alterrors'] unless e['alterrors'].empty?
125
- end
126
- e.delete('alterrors')
127
- end
128
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
124
+ # Check each value of DeliveryMatter{}, try to detect the bounce reason.
125
+ e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
126
+ e["command"] = Sisimai::SMTP::Command.find(e["diagnosis"]) if e["command"].empty?
129
127
 
130
128
  if mhead['x-spasign'].to_s == 'NG'
131
129
  # Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by EZweb)
132
130
  # Filtered recipient returns message that include 'X-SPASIGN' header
133
131
  e['reason'] = 'filtered'
134
132
  else
135
- if e['command'] == 'RCPT'
136
- # set "userunknown" when the remote server rejected after RCPT command.
137
- e['reason'] = 'userunknown'
138
- else
139
- # SMTP command is not RCPT
140
- catch :SESSION do
141
- ReFailures.each_key do |r|
142
- # Try to match with each session error message
143
- ReFailures[r].each do |rr|
144
- # Check each error message pattern
145
- next unless e['diagnosis'].include?(rr)
146
- e['reason'] = r
147
- throw :SESSION
148
- end
133
+ # There is no X-SPASIGN header or the value of the header is not "NG"
134
+ catch :FINDREASON do
135
+ Messagesof.each_key do |r|
136
+ # Try to match with each session error message
137
+ Messagesof[r].each do |f|
138
+ # Check each error message pattern
139
+ next unless e['diagnosis'].include?(f)
140
+ e['reason'] = r
141
+ throw :FINDREASON
149
142
  end
150
143
  end
151
-
152
144
  end
153
145
  end
154
- next if e['reason']
146
+ next if e['reason'] != ""
155
147
  next if e['recipient'].end_with?('@ezweb.ne.jp', '@au.com')
156
- e['reason'] = 'userunknown'
148
+ e["reason"] = "userunknown" if e["diagnosis"].start_with?("<")
157
149
  end
158
150
 
159
151
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::FML parses a bounce email which created by fml. Methods in the module are called
3
- # from only Sisimai::Message.
2
+ # Sisimai::Lhost::FML decodes a bounce email which created by fml mailing list server/manager
3
+ # https://www.fml.org/. Methods in the module are called from only Sisimai::Message.
4
4
  module FML
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -38,11 +38,11 @@ module Sisimai::Lhost
38
38
  'securityerror' => ['Security alert:'],
39
39
  }.freeze
40
40
 
41
- # Parse bounce messages from fml mailling list server/manager
41
+ # @abstract Decodes the bounce message from fml mailling list server/manager
42
42
  # @param [Hash] mhead Message headers of a bounce email
43
43
  # @param [String] mbody Message body of a bounce email
44
44
  # @return [Hash] Bounce data list and message/rfc822 part
45
- # @return [Nil] it failed to parse or the arguments are missing
45
+ # @return [Nil] it failed to decode or the arguments are missing
46
46
  # @since v4.22.3
47
47
  def inquire(mhead, mbody)
48
48
  return nil unless mhead['x-mlserver']
@@ -68,7 +68,7 @@ module Sisimai::Lhost
68
68
  p2 = e.rindex('>') || -1
69
69
  if p1 > 0 && p2 > 0
70
70
  # You are not a member of this mailing list <neko-nyaan@example.org>.
71
- if v['recipient']
71
+ if v["recipient"] != ""
72
72
  # There are multiple recipient addresses in the message body.
73
73
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
74
74
  v = dscontents[-1]
@@ -79,7 +79,6 @@ module Sisimai::Lhost
79
79
  else
80
80
  # If you know the general guide of this list, please send mail with
81
81
  # the mail body
82
- v['diagnosis'] ||= ''
83
82
  v['diagnosis'] << e
84
83
  end
85
84
  end
@@ -98,7 +97,7 @@ module Sisimai::Lhost
98
97
  # Error messages in the message body did not matched
99
98
  ErrorTitle.each_key do |f|
100
99
  # Try to match with the Subject string
101
- next unless mhead['subject'] =~ ErrorTitle[f]
100
+ next unless ErrorTitle[f].any? { |a| mhead["subject"].include?(a) }
102
101
  e['reason'] = f
103
102
  break
104
103
  end
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Gmail parses a bounce email which created by Gmail. Methods in the module are
3
- # called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Gmail decodes a bounce email which created by Gmail https://mail.google.com/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module Gmail
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -28,7 +28,7 @@ module Sisimai::Lhost
28
28
  # We recommend contacting the other email provider for further information about the
29
29
  # cause of this error. The error that the other server returned was:
30
30
  # 500 Remote server does not support TLS (state 6).
31
- '6' => { 'command' => 'MAIL', 'reason' => 'systemerror' },
31
+ '6' => { 'command' => 'MAIL', 'reason' => 'failedstarttls' },
32
32
 
33
33
  # https://www.google.td/support/forum/p/gmail/thread?tid=08a60ebf5db24f7b&hl=en
34
34
  # Technical details of permanent failure:
@@ -44,7 +44,7 @@ module Sisimai::Lhost
44
44
  # We recommend contacting the other email provider for further information about the
45
45
  # cause of this error. The error that the other server returned was:
46
46
  # 454 454 TLS missing certificate: error:0200100D:system library:fopen:Permission denied (#4.3.0) (state 9).
47
- '9' => { 'command' => 'AUTH', 'reason' => 'systemerror' },
47
+ '9' => { 'command' => 'AUTH', 'reason' => 'failedstarttls' },
48
48
 
49
49
  # https://www.google.com/support/forum/p/gmail/thread?tid=5cfab8c76ec88638&hl=en
50
50
  # Technical details of permanent failure:
@@ -96,11 +96,11 @@ module Sisimai::Lhost
96
96
  '18' => { 'command' => 'DATA', 'reason' => 'filtered' },
97
97
  }.freeze
98
98
 
99
- # Parse bounce messages from Gmail
99
+ # @abstract Decodes the bounce message from Gmail
100
100
  # @param [Hash] mhead Message headers of a bounce email
101
101
  # @param [String] mbody Message body of a bounce email
102
102
  # @return [Hash] Bounce data list and message/rfc822 part
103
- # @return [Nil] it failed to parse or the arguments are missing
103
+ # @return [Nil] it failed to decode or the arguments are missing
104
104
  def inquire(mhead, mbody)
105
105
  # From: Mail Delivery Subsystem <mailer-daemon@googlemail.com>
106
106
  # Received: from vw-in-f109.1e100.net [74.125.113.109] by ...
@@ -151,6 +151,7 @@ module Sisimai::Lhost
151
151
  return nil unless mhead['from'].end_with?('<mailer-daemon@googlemail.com>')
152
152
  return nil unless mhead['subject'].start_with?('Delivery Status Notification')
153
153
 
154
+ require 'sisimai/address'
154
155
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
155
156
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
156
157
  bodyslices = emailparts[0].split("\n")
@@ -187,7 +188,7 @@ module Sisimai::Lhost
187
188
 
188
189
  if e.start_with?(' ') && e.include?('@')
189
190
  # kijitora@example.jp: 550 5.2.2 <kijitora@example>... Mailbox Full
190
- if v['recipient']
191
+ if v["recipient"] != ""
191
192
  # There are multiple recipient addresses in the message body.
192
193
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
193
194
  v = dscontents[-1]
@@ -198,41 +199,44 @@ module Sisimai::Lhost
198
199
  v['recipient'] = r
199
200
  recipients += 1
200
201
  else
201
- v['diagnosis'] ||= ''
202
- v['diagnosis'] << e + ' '
202
+ v["diagnosis"] << e << " "
203
203
  end
204
204
  end
205
205
  return nil unless recipients > 0
206
206
 
207
+ require 'sisimai/string'
208
+ require 'sisimai/rfc1123'
207
209
  dscontents.each do |e|
208
210
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
209
211
 
210
- unless e['rhost']
212
+ if Sisimai::String.aligned(e['diagnosis'], [' by ', '. [', ']. '])
211
213
  # Get the value of remote host
212
- if Sisimai::String.aligned(e['diagnosis'], [' by ', '. [', ']. '])
213
- # Google tried to deliver your message, but it was rejected by the server for the recipient
214
- # domain example.jp by mx.example.jp. [192.0.2.153].
215
- p1 = e['diagnosis'].rindex(' by ') || -1
216
- p2 = e['diagnosis'].rindex('. [' ) || -1
217
- hostname = e['diagnosis'][p1 + 4, p2 - p1 - 4]
218
- ipv4addr = e['diagnosis'][p2 + 3, e['diagnosis'].rindex(']. ') - p2 - 3]
219
- lastchar = hostname[-1, 1].upcase.ord
214
+ # Google tried to deliver your message, but it was rejected by the server for the recipient
215
+ # domain example.jp by mx.example.jp. [192.0.2.153].
216
+ p1 = e['diagnosis'].rindex(' by ') || -1
217
+ p2 = e['diagnosis'].rindex('. [' ) || -1
218
+ hostname = e['diagnosis'][p1 + 4, p2 - p1 - 4]
219
+ ipv4addr = e['diagnosis'][p2 + 3, e['diagnosis'].rindex(']. ') - p2 - 3]
220
220
 
221
- e['rhost'] = hostname if lastchar > 64 && lastchar < 91
222
- e['rhost'] ||= ipv4addr
223
- end
221
+ e['rhost'] = hostname if Sisimai::RFC1123.is_internethost(hostname)
222
+ e['rhost'] = ipv4addr if e["rhost"].empty?
224
223
  end
225
224
 
226
- p1 = e['diagnosis'].rindex(' ') || -1
227
- p2 = e['diagnosis'].rindex(')') || -1
228
- statecode0 = e['diagnosis'][p1 + 1, p2 - p1 - 1] || 0
225
+ while true do
226
+ # Find "(state 18)" and pick "18" as a key of statetable
227
+ p1 = e['diagnosis'].rindex(' (state '); break unless p1
228
+ p2 = e['diagnosis'].rindex(')'); break unless p2
229
+ break if p1 > p2
230
+ cu = e['diagnosis'][p1 + 8, p2 - p1 - 8]
231
+ break if cu.empty?
232
+ break unless StateTable[cu]
233
+ e['reason'] = StateTable[cu]['reason']
234
+ e['command'] = StateTable[cu]['command']
235
+ break
236
+ end
229
237
 
230
- if StateTable[statecode0]
231
- # (state *)
232
- e['reason'] = StateTable[statecode0]['reason']
233
- e['command'] = StateTable[statecode0]['command']
234
- else
235
- # No state code
238
+ if e['reason'].empty?
239
+ # There is no no state code in the error message
236
240
  MessagesOf.each_key do |r|
237
241
  # Verify each regular expression of session errors
238
242
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
@@ -240,10 +244,10 @@ module Sisimai::Lhost
240
244
  break
241
245
  end
242
246
  end
243
- next unless e['reason']
247
+ next if e['reason'].empty?
244
248
 
245
249
  # Set pseudo status code
246
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
250
+ e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
247
251
  next if e['status'].size == 0 || e['status'].include?('.0')
248
252
  e['reason'] = Sisimai::SMTP::Status.name(e['status']).to_s || ''
249
253
  end
@@ -1,6 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::GMX parses a bounce email which created by GMX. Methods in the module are called
3
- # from only Sisimai::Message.
2
+ # Sisimai::Lhost::GMX decodes a bounce email which created by GMX https://gmx.net/.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module GMX
5
5
  class << self
6
6
  require 'sisimai/lhost'
@@ -10,11 +10,11 @@ module Sisimai::Lhost
10
10
  StartingOf = { message: ['This message was created automatically by mail delivery software'] }.freeze
11
11
  MessagesOf = { 'expired' => ['delivery retry timeout exceeded'] }.freeze
12
12
 
13
- # Parse bounce messages from GMX
13
+ # @abstract Decodes the bounce message from GMX
14
14
  # @param [Hash] mhead Message headers of a bounce email
15
15
  # @param [String] mbody Message body of a bounce email
16
16
  # @return [Hash] Bounce data list and message/rfc822 part
17
- # @return [Nil] it failed to parse or the arguments are missing
17
+ # @return [Nil] it failed to decode or the arguments are missing
18
18
  def inquire(mhead, mbody)
19
19
  # Envelope-To: <kijitora@mail.example.com>
20
20
  # X-GMX-Antispam: 0 (Mail was not recognized as spam); Detail=V3;
@@ -60,7 +60,7 @@ module Sisimai::Lhost
60
60
  #
61
61
  # Reason:
62
62
  # delivery retry timeout exceeded
63
- if v['recipient']
63
+ if v["recipient"] != ""
64
64
  # There are multiple recipient addresses in the message body.
65
65
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
66
66
  v = dscontents[-1]
@@ -76,21 +76,9 @@ module Sisimai::Lhost
76
76
  # host: mx.example.jp
77
77
  v['rhost'] = e[6, e.size]
78
78
  else
79
- # Get error message
80
- if Sisimai::SMTP::Status.find(e) || Sisimai::String.aligned(e, ['<', '@', '>'])
81
- # 5.1.1 <shironeko@example.jp>... User Unknown
82
- v['diagnosis'] ||= e
83
- else
84
- next if e.empty?
85
- if e.start_with?('Reason:')
86
- # Reason:
87
- # delivery retry timeout exceeded
88
- v['diagnosis'] = e
89
-
90
- elsif v['diagnosis'] == 'Reason:'
91
- v['diagnosis'] = e
92
- end
93
- end
79
+ # Get error messages
80
+ next if e.empty?
81
+ v['diagnosis'] += e + ' '
94
82
  end
95
83
  end
96
84
  return nil unless recipients > 0
@@ -1,20 +1,19 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::GoogleGroups parses a bounce email which created by Google Groups. Methods in the
3
- # module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::GoogleGroups decodes a bounce email which created by Google Groups https://groups.google.com.
3
+ # Methods in the module are called from only Sisimai::Message.
4
4
  module GoogleGroups
5
5
  class << self
6
6
  require 'sisimai/lhost'
7
+ Boundaries = ['----- Original message -----', 'Content-Type: message/rfc822'].freeze
7
8
 
8
- Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['----- Original message -----'].freeze
10
-
11
- # Parse bounce messages from Google Groups
9
+ # @abstract Decodes the bounce message from Google Groups
12
10
  # @param [Hash] mhead Message headers of a bounce email
13
11
  # @param [String] mbody Message body of a bounce email
14
12
  # @return [Hash] Bounce data list and message/rfc822 part
15
- # @return [Nil] it failed to parse or the arguments are missing
13
+ # @return [Nil] it failed to decode or the arguments are missing
16
14
  # @since v4.25.6
17
15
  def inquire(mhead, mbody)
16
+ return nil unless mbody.include?("Google Groups")
18
17
  return nil unless mhead['from'].end_with?('<mailer-daemon@googlemail.com>')
19
18
  return nil unless mhead['subject'].start_with?('Delivery Status Notification')
20
19
  return nil unless mhead['x-failed-recipients']
@@ -39,7 +38,6 @@ module Sisimai::Lhost
39
38
  # Google Groups
40
39
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
41
40
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
42
- recordwide = { 'rhost' => '', 'reason' => '', 'diagnosis' => '' }
43
41
  recipients = 0
44
42
  v = dscontents[-1]
45
43
 
@@ -49,15 +47,18 @@ module Sisimai::Lhost
49
47
  # * This group may not be open to posting.
50
48
  entiremesg = emailparts[0].split(/\n\n/, 5).slice(0, 4).join(' ').tr("\n", ' ');
51
49
  receivedby = mhead['received'] || []
52
- recordwide['diagnosis'] = Sisimai::String.sweep(entiremesg)
53
- recordwide['reason'] = emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4 ? 'rejected' : 'onhold'
54
- recordwide['rhost'] = Sisimai::RFC5322.received(receivedby[0])[1]
50
+ recordwide = {
51
+ 'diagnosis' => Sisimai::String.sweep(entiremesg),
52
+ 'reason' => 'onhold',
53
+ 'rhost' => Sisimai::RFC5322.received(receivedby[0])[1],
54
+ }
55
+ recordwide['reason'] = 'rejected' if emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4
55
56
 
56
57
  mhead['x-failed-recipients'].split(',').each do |e|
57
58
  # X-Failed-Recipients: neko@example.jp, nyaan@example.org, ...
58
59
  next unless Sisimai::Address.is_emailaddress(e)
59
60
 
60
- if v['recipient']
61
+ if v["recipient"] != ""
61
62
  # There are multiple recipient addresses in the message body.
62
63
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
63
64
  v = dscontents[-1]
@@ -0,0 +1,94 @@
1
+ module Sisimai::Lhost
2
+ # Sisimai::Lhost::GoogleWorkspace decodes a bounce email which created by Google Workspace.
3
+ # Methods in the module are called only from Sisimai::Message.
4
+ module GoogleWorkspace
5
+ class << self
6
+ require 'sisimai/lhost'
7
+ require 'sisimai/string'
8
+ require 'sisimai/address'
9
+
10
+ Indicators = Sisimai::Lhost.INDICATORS
11
+ Boundaries = ["Content-Type: message/rfc822", "Content-Type: text/rfc822-headers"].freeze
12
+ StartingOf = {
13
+ message: ["** "],
14
+ error: ["The response was:", "The response from the remote server was:"],
15
+ }.freeze
16
+ MessagesOf = {
17
+ "userunknown" => ["because the address couldn't be found. Check for typos or unnecessary spaces and try again."],
18
+ "notaccept" => ["Null MX"],
19
+ "networkerror" => [" had no relevant answers.", " responded with code NXDOMAIN"],
20
+ }.freeze
21
+
22
+ # @abstract Decodes the bounce message from Google Workspace
23
+ # @param [Hash] mhead Message headers of a bounce email
24
+ # @param [String] mbody Message body of a bounce email
25
+ # @return [Hash] Bounce data list and message/rfc822 part
26
+ # @return [Nil] it failed to decode or the arguments are missing
27
+ # @see https://workspace.google.com/.
28
+ def inquire(mhead, mbody)
29
+ return nil if mbody.include?("\nDiagnostic-Code:")
30
+ return nil if mbody.include?("\nFinal-Recipient:")
31
+ return nil unless mhead["from"].include?('<mailer-daemon@googlemail.com>')
32
+ return nil unless mhead["subject"].include?("Delivery Status Notification")
33
+
34
+ dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
35
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
36
+ bodyslices = emailparts[0].split("\n")
37
+ entiremesg = ""
38
+ readcursor = 0 # (Integer) Points the current cursor position
39
+ recipients = 0 # (Integer) The number of 'Final-Recipient' header
40
+
41
+ while e = bodyslices.shift do
42
+ # Read error messages and delivery status lines from the head of the email to the previous
43
+ # line of the beginning of the original message.
44
+ if readcursor == 0
45
+ # Beginning of the bounce message or message/delivery-status part
46
+ if e.start_with?(StartingOf[:message][0])
47
+ # ** Message not delivered **
48
+ readcursor |= Indicators[:deliverystatus]
49
+ entiremesg << e + " "
50
+ end
51
+ end
52
+ next if (readcursor & Indicators[:deliverystatus]) == 0
53
+ next if e.empty?
54
+
55
+ # ** Message not delivered **
56
+ # You're sending this from a different address or alias using the 'Send mail as' feature.
57
+ # The settings for your 'Send mail as' account are misconfigured or out of date. Check those settings and try resending.
58
+ # Learn more here: https://support.google.com/mail/?p=CustomFromDenied
59
+ # The response was:
60
+ # Unspecified Error (SENT_SECOND_EHLO): Smtp server does not advertise AUTH capability
61
+ next if e.start_with?("Content-Type: ")
62
+ entiremesg << e + " "
63
+ end
64
+
65
+ while recipients == 0 do
66
+ # Pick the recipient address from the value of To: header of the original message after
67
+ # Content-Type: message/rfc822 field
68
+ p0 = emailparts[1].index("\nTo:"); break unless p0
69
+ p1 = emailparts[1].index("\n", p0 + 2)
70
+ cv = Sisimai::Address.s3s4(emailparts[1][p0 + 4, p1 - p0])
71
+ dscontents[0]["recipient"] = cv
72
+ recipients += 1
73
+ end
74
+ return nil if recipients == 0
75
+
76
+ dscontents[0]["diagnosis"] = entiremesg
77
+ dscontents.each do |e|
78
+ # Tidy up the error message in e["diagnosis"], Try to detect the bounce reason.
79
+ e["diagnosis"] = Sisimai::String.sweep(e["diagnosis"])
80
+ MessagesOf.each_key do |r|
81
+ # Guess an reason of the bounce
82
+ next unless MessagesOf[r].any? { |a| e["diagnosis"].include?(a) }
83
+ e["reason"] = r
84
+ break
85
+ end
86
+ end
87
+
88
+ return { "ds" => dscontents, "rfc822" => emailparts[1] }
89
+ end
90
+ def description; return "Google Workspace: https://workspace.google.com/"; end
91
+ end
92
+ end
93
+ end
94
+
@@ -1,5 +1,6 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::IMailServer parses a bounce email which created by Ipswitch IMail Server.
2
+ # Sisimai::Lhost::IMailServer decodes a bounce email which created by Progress iMail Server
3
+ # https://community.progress.com/s/products/imailserver.
3
4
  # Methods in the module are called from only Sisimai::Message.
4
5
  module IMailServer
5
6
  class << self
@@ -7,20 +8,20 @@ module Sisimai::Lhost
7
8
 
8
9
  Boundaries = ['Original message follows.'].freeze
9
10
  StartingOf = { error: ['Body of message generated response:'] }.freeze
10
- ReFailures = {
11
+ MessagesOf = {
11
12
  'hostunknown' => ['Unknown host'],
12
13
  'userunknown' => ['Unknown user', 'Invalid final delivery userid'],
13
14
  'mailboxfull' => ['User mailbox exceeds allowed size'],
14
15
  'virusdetected' => ['Requested action not taken: virus detected'],
15
- 'undefined' => ['undeliverable to'],
16
+ 'spamdetected' => ['Blacklisted URL in message'],
16
17
  'expired' => ['Delivery failed '],
17
18
  }.freeze
18
19
 
19
- # Parse bounce messages from IMailServer
20
+ # @abstract Decodes the bounce message from Progress iMail Server
20
21
  # @param [Hash] mhead Message headers of a bounce email
21
22
  # @param [String] mbody Message body of a bounce email
22
23
  # @return [Hash] Bounce data list and message/rfc822 part
23
- # @return [Nil] it failed to parse or the arguments are missing
24
+ # @return [Nil] it failed to decode or the arguments are missing
24
25
  def inquire(mhead, mbody)
25
26
  # X-Mailer: <SMTP32 v8.22>
26
27
  match = 0
@@ -44,24 +45,15 @@ module Sisimai::Lhost
44
45
  v = dscontents[-1]
45
46
 
46
47
  p0 = e.index(': ') || -1
47
- if p0 > 8 && Sisimai::String.aligned(e, [': ', '@'])
48
+ if (p0 > 8 && Sisimai::String.aligned(e, [': ', '@'])) || e.start_with?('undeliverable ')
48
49
  # Unknown user: kijitora@example.com
49
- if v['recipient']
50
- # There are multiple recipient addresses in the message body.
51
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
52
- v = dscontents[-1]
53
- end
54
- v['diagnosis'] = e
55
- v['recipient'] = Sisimai::Address.s3s4(e[p0 + 2, e.size])
56
- recipients += 1
57
-
58
- elsif e.start_with?('undeliverable ')
59
50
  # undeliverable to kijitora@example.com
60
- if v['recipient']
51
+ if v["recipient"] != ""
61
52
  # There are multiple recipient addresses in the message body.
62
53
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
63
54
  v = dscontents[-1]
64
55
  end
56
+ v['diagnosis'] = e
65
57
  v['recipient'] = Sisimai::Address.s3s4(e)
66
58
  recipients += 1
67
59
  else
@@ -87,9 +79,9 @@ module Sisimai::Lhost
87
79
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
88
80
  e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
89
81
 
90
- ReFailures.each_key do |r|
82
+ MessagesOf.each_key do |r|
91
83
  # Verify each regular expression of session errors
92
- next unless ReFailures[r].any? { |a| e['diagnosis'].include?(a) }
84
+ next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
93
85
  e['reason'] = r
94
86
  break
95
87
  end