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
data/lib/sisimai/fact.rb CHANGED
@@ -1,27 +1,33 @@
1
1
  module Sisimai
2
- # Sisimai::Fact generate parsed data
2
+ # Sisimai::Fact generate the list of decoded bounce data
3
3
  class Fact
4
4
  require 'sisimai/message'
5
+ require 'sisimai/rfc791'
6
+ require 'sisimai/rfc1123'
5
7
  require 'sisimai/rfc1894'
6
8
  require 'sisimai/rfc5322'
7
9
  require 'sisimai/reason'
8
10
  require 'sisimai/address'
9
11
  require 'sisimai/datetime'
10
12
  require 'sisimai/time'
11
- require 'sisimai/smtp/error'
13
+ require 'sisimai/smtp/failure'
12
14
  require 'sisimai/smtp/command'
13
15
  require 'sisimai/string'
14
16
  require 'sisimai/rhost'
17
+ require 'sisimai/lda'
15
18
 
16
19
  @@rwaccessors = [
17
20
  :action, # [String] The value of Action: header
18
21
  :addresser, # [Sisimai::Address] From address
19
22
  :alias, # [String] Alias of the recipient address
20
23
  :catch, # [?] Results generated by hook method
24
+ :command, # [String] The last SMTP command
25
+ :decodedby, # [String] MTA module name since v5.2.0
21
26
  :deliverystatus, # [String] Delivery Status(DSN)
22
- :destination, # [String] The domain part of the "recipinet"
27
+ :destination, # [String] The domain part of the "recipient"
23
28
  :diagnosticcode, # [String] Diagnostic-Code: Header
24
29
  :diagnostictype, # [String] The 1st part of Diagnostic-Code: Header
30
+ :feedbackid, # [String] The value of Feedback-ID: header of the original message
25
31
  :feedbacktype, # [String] Feedback Type
26
32
  :hardbounce, # [Boolean] true = Hard bounce, false = is not a hard bounce
27
33
  :lhost, # [String] local host name/Local MTA
@@ -33,8 +39,6 @@ module Sisimai
33
39
  :replycode, # [String] SMTP Reply Code
34
40
  :rhost, # [String] Remote host name/Remote MTA
35
41
  :senderdomain, # [String] The domain part of the "addresser"
36
- :smtpagent, # [String] Module(Engine) name
37
- :smtpcommand, # [String] The last SMTP command
38
42
  :subject, # [String] UTF-8 Subject text
39
43
  :timestamp, # [Sisimai::Time] Date: header in the original message
40
44
  :timezoneoffset, # [Integer] Time zone offset(seconds)
@@ -43,7 +47,7 @@ module Sisimai
43
47
  attr_accessor(*@@rwaccessors)
44
48
 
45
49
  RetryIndex = Sisimai::Reason.retry
46
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS(:all)
50
+ RFC822Head = Sisimai::RFC5322.HEADERTABLE
47
51
  ActionList = { delayed: 1, delivered: 1, expanded: 1, failed: 1, relayed: 1 };
48
52
 
49
53
  if RUBY_PLATFORM.start_with?('java')
@@ -67,10 +71,13 @@ module Sisimai
67
71
  @addresser = argvs['addresser']
68
72
  @action = argvs['action']
69
73
  @catch = argvs['catch']
74
+ @command = argvs['command']
75
+ @decodedby = argvs['decodedby']
70
76
  @diagnosticcode = argvs['diagnosticcode']
71
77
  @diagnostictype = argvs['diagnostictype']
72
78
  @deliverystatus = argvs['deliverystatus']
73
79
  @destination = argvs['recipient'].host
80
+ @feedbackid = argvs["feedbackid"]
74
81
  @feedbacktype = argvs['feedbacktype']
75
82
  @hardbounce = argvs['hardbounce']
76
83
  @lhost = argvs['lhost']
@@ -82,8 +89,6 @@ module Sisimai
82
89
  @replycode = argvs['replycode']
83
90
  @rhost = argvs['rhost']
84
91
  @senderdomain = argvs['addresser'].host
85
- @smtpagent = argvs['smtpagent']
86
- @smtpcommand = argvs['smtpcommand']
87
92
  @subject = argvs['subject']
88
93
  @token = argvs['token']
89
94
  @timestamp = argvs['timestamp']
@@ -93,11 +98,9 @@ module Sisimai
93
98
  # Constructor of Sisimai::Fact
94
99
  # @param [Hash] argvs
95
100
  # @options argvs [String] data Entire email message
96
- # @options argvs [Boolean] delivered Include the result which has "delivered" reason
97
- # @options argvs [Boolean] vacation Include the result which has "vacation" reason
98
- # @options argvs [Proc] hook Proc object of callback method
99
- # @options argvs [Array] load User defined MTA module list
100
- # @options argvs [Array] order The order of MTA modules
101
+ # @options argvs [Boolean] delivered true if the result which has "delivered" reason is included
102
+ # @options argvs [Boolean] vacation true if the result which has "vacation" reason is included
103
+ # @options argvs [Proc] hook Proc object of the callback method
101
104
  # @options argvs [String] origin Path to the original email file
102
105
  # @return [Array] Array of Sisimai::Fact objects
103
106
  def self.rise(**argvs)
@@ -105,11 +108,8 @@ module Sisimai
105
108
  return nil unless argvs.is_a? Hash
106
109
 
107
110
  email = argvs[:data]; return nil unless email
108
- loads = argvs[:load] || nil
109
- order = argvs[:order] || nil
110
- args1 = { data: email, hook: argvs[:hook], load: loads, order: order }
111
+ args1 = { data: email, hook: argvs[:hook] }
111
112
  mesg1 = Sisimai::Message.rise(**args1)
112
-
113
113
  return nil unless mesg1
114
114
  return nil unless mesg1['ds']
115
115
  return nil unless mesg1['rfc822']
@@ -120,55 +120,48 @@ module Sisimai
120
120
 
121
121
  while e = deliveries.shift do
122
122
  # Create parameters for each Sisimai::Fact object
123
- o = {} # To be passed to each accessor of Sisimai::Fact
124
- p = {
125
- 'action' => e['action'] || '',
126
- 'alias' => e['alias'] || '',
127
- 'catch' => mesg1['catch'] || nil,
128
- 'deliverystatus' => e['status'] || '',
129
- 'diagnosticcode' => e['diagnosis'] || '',
130
- 'diagnostictype' => e['spec'] || '',
131
- 'feedbacktype' => e['feedbacktype'] || '',
132
- 'hardbounce' => false,
133
- 'lhost' => e['lhost'] || '',
134
- 'origin' => argvs[:origin],
135
- 'reason' => e['reason'] || '',
136
- 'recipient' => e['recipient'] || '',
137
- 'replycode' => e['replycode'] || '',
138
- 'rhost' => e['rhost'] || '',
139
- 'smtpagent' => e['agent'] || '',
140
- 'smtpcommand' => e['command'] || '',
123
+ next if e['recipient'].size < 5
124
+ next if ! argvs[:vacation] && e['reason'] == 'vacation'
125
+ next if ! argvs[:delivered] && e['status'].start_with?('2.')
126
+
127
+ thing = {} # To be passed to each accessor of Sisimai::Fact
128
+ piece = {
129
+ "action" => e["action"],
130
+ "alias" => e["alias"],
131
+ "catch" => mesg1["catch"] || nil,
132
+ "command" => e["command"],
133
+ "deliverystatus" => e["status"],
134
+ "diagnosticcode" => e["diagnosis"],
135
+ "diagnostictype" => e["spec"],
136
+ "feedbacktype" => e["feedbacktype"],
137
+ "hardbounce" => false,
138
+ "lhost" => e["lhost"],
139
+ "origin" => argvs[:origin],
140
+ "reason" => e["reason"],
141
+ "recipient" => e["recipient"],
142
+ "replycode" => e["replycode"],
143
+ "rhost" => e["rhost"],
144
+ "decodedby" => e["agent"],
141
145
  }
142
- unless argvs[:delivered]
143
- # Skip if the value of "deliverystatus" begins with "2." such as 2.1.5
144
- next if p['deliverystatus'].start_with?('2.')
145
- end
146
-
147
- unless argvs[:vacation]
148
- # Skip if the value of "reason" is "vacation"
149
- next if p['reason'] == 'vacation'
150
- end
151
146
 
152
- # EMAILADDRESS: Detect email address from message/rfc822 part
147
+ # EMAILADDRESS: Detect an email address from message/rfc822 part
153
148
  RFC822Head[:addresser].each do |f|
154
149
  # Check each header in message/rfc822 part
155
- g = f.downcase
156
- next unless rfc822data[g]
157
- next if rfc822data[g].empty?
150
+ next unless rfc822data[f]
151
+ next if rfc822data[f].empty?
158
152
 
159
- j = Sisimai::Address.find(rfc822data[g]) || next
160
- p['addresser'] = j.shift
153
+ j = Sisimai::Address.find(rfc822data[f]) || next
154
+ piece['addresser'] = j.shift
161
155
  break
162
156
  end
163
157
 
164
- unless p['addresser']
158
+ unless piece['addresser']
165
159
  # Fallback: Get the sender address from the header of the bounced email if the address is
166
160
  # not set at loop above.
167
161
  j = Sisimai::Address.find(mesg1['header']['to']) || []
168
- p['addresser'] = j.shift
162
+ piece['addresser'] = j.shift
169
163
  end
170
- next unless p['addresser']
171
- next unless p['recipient']
164
+ next unless piece['addresser']
172
165
 
173
166
  # TIMESTAMP: Convert from a time stamp or a date string to a machine time.
174
167
  datestring = nil
@@ -184,54 +177,91 @@ module Sisimai
184
177
 
185
178
  # Set "date" getting from the value of "Date" in the bounce message
186
179
  datevalues << mesg1['header']['date'] if datevalues.size < 2
187
-
188
180
  while v = datevalues.shift do
189
181
  # Parse each date value in the array
190
- datestring = Sisimai::DateTime.parse(v)
191
- break if datestring
192
- end
182
+ datestring = Sisimai::DateTime.parse(v) || next
193
183
 
194
- if datestring && cv = datestring.match(/\A(.+)[ ]+([-+]\d{4})\z/)
195
- # Get the value of timezone offset from datestring: Wed, 26 Feb 2014 06:05:48 -0500
196
- datestring = cv[1]
197
- zoneoffset = Sisimai::DateTime.tz2second(cv[2])
198
- p['timezoneoffset'] = cv[2]
184
+ if cv = datestring.match(/\A(.+)[ ]+([-+]\d{4})\z/)
185
+ # Get the value of timezone offset from datestring: Wed, 26 Feb 2014 06:05:48 -0500
186
+ datestring = cv[1]
187
+ zoneoffset = Sisimai::DateTime.tz2second(cv[2])
188
+ piece['timezoneoffset'] = cv[2]
189
+ end
190
+ break if datestring
199
191
  end
200
192
 
201
193
  begin
202
194
  # Convert from the date string to an object then calculate time zone offset.
203
195
  t = TimeModule.strptime(datestring, '%a, %d %b %Y %T')
204
- p['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
196
+ piece['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
205
197
  rescue
206
198
  warn ' ***warning: Failed to strptime ' << datestring.to_s
207
199
  end
208
- next unless p['timestamp']
200
+ next unless piece['timestamp']
209
201
 
210
202
  # OTHER_TEXT_HEADERS:
211
- rr = mesg1['header']['received'] || []
212
- unless rr.empty?
213
- # Get a localhost and a remote host name from Received header.
214
- p['rhost'] = Sisimai::RFC5322.received(rr[-1])[1] if p['rhost'].empty?
215
- p['lhost'] = '' if p['rhost'] == p['lhost']
216
- p['lhost'] = Sisimai::RFC5322.received(rr[ 0])[0] if p['lhost'].empty?
203
+ recv = mesg1["header"]["received"] || []
204
+ if piece["rhost"].empty?
205
+ # Try to pick a remote hostname from Received: headers of the bounce message
206
+ ir = Sisimai::RFC1123.find(e["diagnosis"])
207
+ piece["rhost"] = ir if Sisimai::RFC1123.is_internethost(ir)
208
+
209
+ if piece["rhost"].empty?
210
+ # The remote hostname in the error message did not exist or is not a valid
211
+ # internet hostname
212
+ recv.reverse.each do |re|
213
+ # Check the Received: headers backwards and get a remote hostname
214
+ break if piece["rhost"].size > 0
215
+ cv = Sisimai::RFC5322.received(re)[0]
216
+ next unless Sisimai::RFC1123.is_internethost(cv)
217
+ piece['rhost'] = cv
218
+ end
219
+ end
220
+ end
221
+ piece["lhost"] = "" if piece["rhost"] == piece["lhost"]
222
+
223
+ if piece["lhost"].empty?
224
+ # Try to pick a local hostname from Received: headers of the bounce message
225
+ recv.each do |le|
226
+ # Check the Received: headers backwards and get a local hostname
227
+ cv = Sisimai::RFC5322.received(le)[0]
228
+ next unless Sisimai::RFC1123.is_internethost(cv)
229
+ piece['lhost'] = cv
230
+ break
231
+ end
217
232
  end
218
233
 
219
234
  # Remove square brackets and curly brackets from the host variable
220
235
  %w[rhost lhost].each do |v|
221
- p[v] = p[v].split('@')[-1] if p[v].include?('@')
222
- p[v].delete!('[]()') # Remove square brackets and curly brackets from the host variable
223
- p[v].sub!(/\A.+=/, '') # Remove string before "="
224
- p[v].chomp!("\r") if p[v].end_with?("\r") # Remove CR at the end of the value
225
-
226
- # Check space character in each value and get the first element
227
- p[v] = p[v].split(' ', 2).shift if p[v].include?(' ')
228
- p[v].chomp!('.') if p[v].end_with?('.') # Remove "." at the end of the value
236
+ next if piece[v].empty?
237
+
238
+ if piece[v].include?('@')
239
+ # Use the domain part as a remote/local host when the value is an email address
240
+ piece[v] = piece[v].split('@')[-1]
241
+ end
242
+ piece[v].delete!('[]()') # Remove square brackets and curly brackets from the host variable
243
+ piece[v].sub!(/\A.+=/, '') # Remove string before "="
244
+ piece[v].sub!("\r", '') # Remove CR at the end of the value
245
+
246
+ if piece[v].include?(' ')
247
+ # Check space character in each value and get the first hostname
248
+ ee = piece[v].split(' ')
249
+ ee.each do |w|
250
+ # get a hostname from the string like "127.0.0.1 x109-20.example.com 192.0.2.20"
251
+ # or "mx.sp.example.jp 192.0.2.135"
252
+ next if Sisimai::RFC791.is_ipv4address(w)
253
+ piece[v] = w
254
+ break
255
+ end
256
+ end
257
+ piece[v] = ee[0] if piece[v].include?(' ')
258
+ piece[v].chomp!('.') if piece[v].end_with?('.') # Remove "." at the end of the value
229
259
  end
230
260
 
231
261
  # Subject: header of the original message
232
- p['subject'] = rfc822data['subject'] || ''
233
- p['subject'].scrub!('?')
234
- p['subject'].chomp!("\r") if p['subject'].end_with?("\r")
262
+ piece['subject'] = rfc822data['subject'] || ''
263
+ piece['subject'].scrub!('?')
264
+ piece['subject'].chomp!("\r") if piece['subject'].end_with?("\r")
235
265
 
236
266
  # The value of "List-Id" header
237
267
  if Sisimai::String.aligned(rfc822data['list-id'], ['<', '.', '>'])
@@ -239,10 +269,10 @@ module Sisimai
239
269
  # Get the value of List-Id header: "List name <list-id@example.org>"
240
270
  p0 = rfc822data['list-id'].index('<') + 1
241
271
  p1 = rfc822data['list-id'].index('>')
242
- p['listid'] = rfc822data['list-id'][p0, p1 - p0]
272
+ piece['listid'] = rfc822data['list-id'][p0, p1 - p0]
243
273
  else
244
274
  # Invalid value of the List-Id: field
245
- p['listid'] = ''
275
+ piece['listid'] = ''
246
276
  end
247
277
 
248
278
  # The value of "Message-Id" header
@@ -251,26 +281,26 @@ module Sisimai
251
281
  # Leave only string inside of angle brackets(<>)
252
282
  p0 = rfc822data['message-id'].index('<') + 1
253
283
  p1 = rfc822data['message-id'].index('>')
254
- p['messageid'] = rfc822data['message-id'][p0, p1 - p0]
284
+ piece['messageid'] = rfc822data['message-id'][p0, p1 - p0]
255
285
  else
256
286
  # Invalid value of the Message-Id: field
257
- p['messageid'] = ''
287
+ piece['messageid'] = ''
258
288
  end
259
289
 
260
290
  # CHECK_DELIVERY_STATUS_VALUE: Cleanup the value of "Diagnostic-Code:" header
261
- if p['diagnosticcode'].to_s.size > 0
291
+ if piece['diagnosticcode'].to_s.size > 0
262
292
  # Get an SMTP Reply Code and an SMTP Enhanced Status Code
263
- p['diagnosticcode'].chop if p['diagnosticcode'][-1, 1] == "\r"
293
+ piece['diagnosticcode'].chop if piece['diagnosticcode'][-1, 1] == "\r"
264
294
 
265
- cs = Sisimai::SMTP::Status.find(p['diagnosticcode']) || ''
266
- cr = Sisimai::SMTP::Reply.find(p['diagnosticcode'], cs) || ''
267
- p['deliverystatus'] = Sisimai::SMTP::Status.prefer(p['deliverystatus'], cs, cr)
295
+ cs = Sisimai::SMTP::Status.find(piece['diagnosticcode'])
296
+ cr = Sisimai::SMTP::Reply.find(piece['diagnosticcode'], cs)
297
+ piece['deliverystatus'] = Sisimai::SMTP::Status.prefer(piece['deliverystatus'], cs, cr)
268
298
 
269
299
  if cr.size == 3
270
300
  # There is an SMTP reply code in the error message
271
- p['replycode'] = cr if p['replycode'].to_s.empty?
301
+ piece['replycode'] = cr if piece['replycode'].empty?
272
302
 
273
- if p['diagnosticcode'].include?(cr + '-')
303
+ if piece['diagnosticcode'].include?(cr + '-')
274
304
  # 550-5.7.1 [192.0.2.222] Our system has detected that this message is
275
305
  # 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,
276
306
  # 550-5.7.1 this message has been blocked. Please visit
@@ -286,80 +316,84 @@ module Sisimai
286
316
  ['-', " "].each do |q|
287
317
  # Remove strings: "550-5.7.1", and "550 5.7.1" from the error message
288
318
  cx = sprintf("%s%s%s", cr, q, cs)
289
- p0 = p['diagnosticcode'].index(cx)
319
+ p0 = piece['diagnosticcode'].index(cx)
290
320
  while p0
291
321
  # Remove strings like "550-5.7.1"
292
- p['diagnosticcode'][p0, cx.size] = ''
293
- p0 = p['diagnosticcode'].index(cx)
322
+ piece['diagnosticcode'][p0, cx.size] = ''
323
+ p0 = piece['diagnosticcode'].index(cx)
294
324
  end
295
325
 
296
326
  # Remove "553-" and "553 " (SMTP reply code only) from the error message
297
327
  cx = sprintf("%s%s", cr, q)
298
- p0 = p['diagnosticcode'].index(cx)
328
+ p0 = piece['diagnosticcode'].index(cx)
299
329
  while p0
300
330
  # Remove strings like "553-"
301
- p['diagnosticcode'][p0, cx.size] = ''
302
- p0 = p['diagnosticcode'].index(cx)
331
+ piece['diagnosticcode'][p0, cx.size] = ''
332
+ p0 = piece['diagnosticcode'].index(cx)
303
333
  end
304
334
  end
305
335
 
306
- if p['diagnosticcode'].index(cr).to_i > 1
336
+ if piece['diagnosticcode'].index(cr).to_i > 1
307
337
  # Add "550 5.1.1" into the head of the error message when the error message does not
308
338
  # begin with "550"
309
- p['diagnosticcode'] = sprintf("%s %s %s", cr, cs, p['diagnosticcode'])
339
+ piece['diagnosticcode'] = sprintf("%s %s %s", cr, cs, piece['diagnosticcode'])
310
340
  end
311
341
  end
312
342
  end
313
343
 
314
- p1 = p['diagnosticcode'].downcase.index('<html>')
315
- p2 = p['diagnosticcode'].downcase.index('</html>')
316
- p['diagnosticcode'][p1, p2 + 7 - p1] = '' if p1 && p2
317
- p['diagnosticcode'] = Sisimai::String.sweep(p['diagnosticcode'])
344
+ dc = piece['diagnosticcode'].downcase
345
+ p1 = dc.index('<html>')
346
+ p2 = dc.index('</html>')
347
+ piece['diagnosticcode'][p1, p2 + 7 - p1] = '' if p1 && p2
348
+ piece['diagnosticcode'] = Sisimai::String.sweep(piece['diagnosticcode'])
318
349
  end
319
350
 
320
- if Sisimai::String.is_8bit(p['diagnosticcode'])
351
+ if Sisimai::String.is_8bit(piece['diagnosticcode'])
321
352
  # To avoid incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError
322
- p['diagnosticcode'] = p['diagnosticcode'].force_encoding('UTF-8').scrub('?')
353
+ piece['diagnosticcode'] = piece['diagnosticcode'].force_encoding('UTF-8').scrub('?')
323
354
  end
324
355
 
325
- p['diagnostictype'] = nil if p['diagnostictype'].empty?
326
- p['diagnostictype'] ||= 'X-UNIX' if p['reason'] == 'mailererror'
327
- p['diagnostictype'] ||= 'SMTP' unless %w[feedback vacation].include?(p['reason'])
356
+ piece["diagnostictype"] = "X-UNIX" if piece["reason"] == "mailererror"
357
+ if piece["diagnostictype"].empty?
358
+ piece["diagnostictype"] = "SMTP" unless %w[feedback vacation].include?(piece["reason"])
359
+ end
328
360
 
329
361
  # Check the value of SMTP command
330
- p['smtpcommand'] = '' unless Sisimai::SMTP::Command.test(p['smtpcommand'])
362
+ piece['command'] = '' unless Sisimai::SMTP::Command.test(piece['command'])
331
363
 
332
364
  # Create parameters for the constructor
333
- as = Sisimai::Address.new(p['addresser']) || next; next if as.void
334
- ar = Sisimai::Address.new(address: p['recipient']) || next; next if ar.void
365
+ as = Sisimai::Address.new(piece['addresser']) || next; next if as.void
366
+ ar = Sisimai::Address.new(address: piece['recipient']) || next; next if ar.void
335
367
  ea = %w[
336
- action deliverystatus diagnosticcode diagnostictype feedbacktype lhost listid messageid
337
- origin reason replycode rhost smtpagent smtpcommand subject
368
+ action command decodedby deliverystatus diagnosticcode diagnostictype feedbacktype lhost
369
+ listid messageid origin reason replycode rhost subject
338
370
  ]
339
371
 
340
- o = {
372
+ thing = {
341
373
  'addresser' => as,
342
374
  'recipient' => ar,
343
375
  'senderdomain' => as.host,
344
376
  'destination' => ar.host,
345
- 'alias' => p['alias'] || ar.alias,
346
- 'token' => Sisimai::String.token(as.address, ar.address, p['timestamp']),
377
+ 'alias' => piece['alias'] || ar.alias,
378
+ 'token' => Sisimai::String.token(as.address, ar.address, piece['timestamp']),
347
379
  }
380
+ ea.each { |q| thing[q] = piece[q] if thing[q].nil? || thing[q].empty? }
348
381
 
349
382
  # Other accessors
350
- ea.each { |q| o[q] ||= p[q] || '' }
351
- o['catch'] = p['catch'] || nil
352
- o['hardbounce'] = p['hardbounce']
353
- o['replycode'] = Sisimai::SMTP::Reply.find(p['diagnosticcode']).to_s if o['replycode'].empty?
354
- o['timestamp'] = TimeModule.parse(::Time.at(p['timestamp']).to_s)
355
- o['timezoneoffset'] = p['timezoneoffset'] || '+0000'
383
+ thing['catch'] = piece['catch'] || nil
384
+ thing["feedbackid"] = ""
385
+ thing['hardbounce'] = piece['hardbounce']
386
+ thing['replycode'] = Sisimai::SMTP::Reply.find(piece['diagnosticcode']) if thing['replycode'].empty?
387
+ thing['timestamp'] = TimeModule.parse(::Time.at(piece['timestamp']).to_s)
388
+ thing['timezoneoffset'] = piece['timezoneoffset'] || '+0000'
389
+ ea.each { |q| thing[q] = piece[q] if thing[q].empty? }
356
390
 
357
391
  # ALIAS
358
392
  while true do
359
393
  # Look up the Envelope-To address from the Received: header in the original message
360
- # when the recipient address is same with the value of o['alias'].
361
- break if o['alias'].empty?
362
- break if o['recipient'].address != o['alias']
394
+ # when the recipient address is same with the value of thing['alias'].
395
+ break if thing['alias'].empty?
396
+ break if thing['recipient'].address != thing['alias']
363
397
  break unless rfc822data.has_key?('received')
364
398
  break if rfc822data['received'].empty?
365
399
 
@@ -371,94 +405,89 @@ module Sisimai
371
405
  next if af.empty?
372
406
  next if af[5].empty?
373
407
  next unless Sisimai::Address.is_emailaddress(af[5])
374
- next if o['recipient'].address == af[5]
408
+ next if thing['recipient'].address == af[5]
375
409
 
376
- o['alias'] = af[5]
410
+ thing['alias'] = af[5]
377
411
  break
378
412
  end
379
413
  break
380
414
  end
381
- o['alias'] = '' if o['alias'] == o['recipient'].address
415
+ thing['alias'] = '' if thing['alias'] == thing['recipient'].address
382
416
 
383
417
  # REASON: Decide the reason of email bounce
384
- if o['reason'].empty? || RetryIndex[o['reason']]
385
- # The value of "reason" is empty or is needed to check with other values again
386
- re = ''; de = o['destination']
387
- re = Sisimai::Rhost.get(o) if Sisimai::Rhost.match(o['rhost'])
388
- if re.empty?
389
- # Failed to detect a bounce reason by the value of "rhost"
390
- re = Sisimai::Rhost.get(o, de) if Sisimai::Rhost.match(de)
391
- re = Sisimai::Reason.get(o) if re.empty?
392
- re = 'undefined' if re.empty?
418
+ while true
419
+ if thing["reason"].empty? || RetryIndex[thing["reason"]]
420
+ # The value of "reason" is empty or is needed to check with other values again
421
+ re = thing["reason"].empty? ? "undefined" : thing["reason"]
422
+ cr = Sisimai::LDA.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
423
+ cr = Sisimai::Rhost.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
424
+ cr = Sisimai::Reason.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
425
+ thing["reason"] = thing["diagnosticcode"].size > 0 ? "onhold" : re
426
+ break
393
427
  end
394
- o['reason'] = re
428
+ break
395
429
  end
396
430
 
397
431
  # HARDBOUNCE: Set the value of "hardbounce", default value of "bouncebounce" is false
398
- if o['reason'] == 'delivered' || o['reason'] == 'feedback' || o['reason'] == 'vacation'
399
- # The value of "reason" is "delivered", "vacation" or "feedback".
400
- o['replycode'] = '' unless o['reason'] == 'delivered'
432
+ if thing['reason'] == 'delivered' || thing['reason'] == 'feedback' || thing['reason'] == 'vacation'
433
+ # Delete the value of ReplyCode when the Reason is "feedback" or "vacation"
434
+ thing['replycode'] = '' unless thing['reason'] == 'delivered'
401
435
  else
402
- smtperrors = p['deliverystatus'] + ' ' << p['diagnosticcode']
436
+ # The reason is not "delivered", or "feedback", or "vacation"
437
+ smtperrors = piece['deliverystatus'] + ' ' << piece['diagnosticcode']
403
438
  smtperrors = '' if smtperrors.size < 4
404
- softorhard = Sisimai::SMTP::Error.soft_or_hard(o['reason'], smtperrors)
405
- o['hardbounce'] = true if softorhard == 'hard'
439
+ thing['hardbounce'] = Sisimai::SMTP::Failure.is_hardbounce(thing['reason'], smtperrors)
406
440
  end
407
441
 
408
442
  # DELIVERYSTATUS: Set a pseudo status code if the value of "deliverystatus" is empty
409
- if o['deliverystatus'].empty?
410
- smtperrors = p['replycode'] + ' ' << p['diagnosticcode']
443
+ if thing['deliverystatus'].empty?
444
+ smtperrors = piece['replycode'] + ' ' << piece['diagnosticcode']
411
445
  smtperrors = '' if smtperrors.size < 4
412
- permanent1 = Sisimai::SMTP::Error.is_permanent(smtperrors)
413
- permanent1 = true if permanent1 == nil
414
- o['deliverystatus'] = Sisimai::SMTP::Status.code(o['reason'], permanent1 ? false : true) || ''
446
+ permanent0 = Sisimai::SMTP::Failure.is_permanent(smtperrors)
447
+ temporary0 = Sisimai::SMTP::Failure.is_temporary(smtperrors)
448
+ temporary1 = temporary0; temporary1 = false if !permanent0 && !temporary1
449
+ thing['deliverystatus'] = Sisimai::SMTP::Status.code(thing['reason'], temporary1) || ''
415
450
  end
416
451
 
417
452
  # REPLYCODE: Check both of the first digit of "deliverystatus" and "replycode"
418
- cx = [o['deliverystatus'][0, 1], o['replycode'][0, 1]]
453
+ cx = [thing['deliverystatus'][0, 1], thing['replycode'][0, 1]]
419
454
  if cx[0] != cx[1]
420
455
  # The class of the "Status:" is defer with the first digit of the reply code
421
- cx[1] = Sisimai::SMTP::Reply.find(p['diagnosticcode'], cx[0]) || ''
422
- o['replycode'] = cx[1].start_with?(cx[0]) ? cx[1] : ''
456
+ cx[1] = Sisimai::SMTP::Reply.find(piece['diagnosticcode'], cx[0])
457
+ thing['replycode'] = cx[1].start_with?(cx[0]) ? cx[1] : ''
423
458
  end
424
459
 
425
- unless ActionList.has_key?(o['action'])
460
+ unless ActionList.has_key?(thing['action'])
426
461
  # There is an action value which is not described at RFC1894
427
- if ox = Sisimai::RFC1894.field('Action: ' << o['action'])
462
+ if ox = Sisimai::RFC1894.field('Action: ' << thing['action'])
428
463
  # Rewrite the value of "Action:" field to the valid value
429
464
  #
430
465
  # The syntax for the action-field is:
431
466
  # action-field = "Action" ":" action-value
432
467
  # action-value = "failed" / "delayed" / "delivered" / "relayed" / "expanded"
433
- o['action'] = ox[2]
468
+ thing['action'] = ox[2]
434
469
  end
435
470
  end
436
- o['action'] = 'delayed' if o['reason'] == 'expired'
437
- if o['action'].empty?
438
- o['action'] = 'failed' if cx[0] == '4' || cx[0] == '5'
439
- end
471
+ thing["action"] = "" if thing["action"].nil?
472
+ thing["action"] = "delivered" if thing["action"].empty? && thing["reason"] == "delivered"
473
+ thing["action"] = "delayed" if thing["action"].empty? && thing["reason"] == "expired"
474
+ thing["action"] = "failed" if thing["action"].empty? && cx[0] == "4" || cx[0] == "5"
475
+
476
+ # Feedback-ID: 1.us-west-2.QHuyeCQrGtIIMGKQfVdUhP9hCQR2LglVOrRamBc+Prk=:AmazonSES
477
+ thing["feedbackid"] = rfc822data["feedback-id"] || ""
440
478
 
441
- listoffact << Sisimai::Fact.new(o)
479
+ listoffact << Sisimai::Fact.new(thing)
442
480
  end
443
481
  return listoffact
444
482
  end
445
483
 
446
- # Emulate "softbounce" accessor for the backward compatible
447
- # @return [Integer]
448
- def softbounce
449
- warn ' ***warning: Sisimai::Fact.softbounce will be removed at v5.1.0. Use Sisimai::Fact.hardbounce instead'
450
- return 0 if self.hardbounce
451
- return -1 if self.reason == 'delivered' || self.reason == 'feedback' || self.reason == 'vacation'
452
- return 1
453
- end
454
-
455
484
  # Convert from Sisimai::Fact object to a Hash
456
485
  # @return [Hash] Hashed data
457
486
  def damn
458
487
  data = {}
459
488
  stringdata = %w[
460
- action alias catch deliverystatus destination diagnosticcode diagnostictype feedbacktype
461
- lhost listid messageid origin reason replycode rhost senderdomain smtpagent smtpcommand
489
+ action alias catch command decodedby deliverystatus destination diagnosticcode diagnostictype
490
+ feedbackid feedbacktype lhost listid messageid origin reason replycode rhost senderdomain
462
491
  subject timezoneoffset token
463
492
  ]
464
493
 
@@ -469,6 +498,10 @@ module Sisimai
469
498
  v['addresser'] = self.addresser.address
470
499
  v['recipient'] = self.recipient.address
471
500
  v['timestamp'] = self.timestamp.to_time.to_i
501
+
502
+ # Backward compatibility until v5.2.0
503
+ v["smtpagent"] = self.decodedby
504
+ v["smtpcommand"] = self.command
472
505
  data = v
473
506
  rescue
474
507
  warn ' ***warning: Failed to execute Sisimai::Fact.damn'
@@ -501,6 +534,8 @@ module Sisimai
501
534
  return self.dump('json')
502
535
  end
503
536
 
537
+ def smtpagent; warn " ***warning: Sisimai::Fact.smtpagent will be removed at v5.5.0"; return self.decodedby; end
538
+ def smtpcomand; warn " ***warning: Sisimai::Fact.smtpcommand will be removed at v5.5.0"; return self.command; end
504
539
  end
505
540
  end
506
541