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,109 +0,0 @@
1
- module Sisimai::Lhost
2
- # Sisimai::Lhost::McAfee parses a bounce email which created by McAfee Email Appliance. Methods in
3
- # the module are called from only Sisimai::Message.
4
- module McAfee
5
- class << self
6
- require 'sisimai/lhost'
7
-
8
- Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['Content-Type: message/rfc822'].freeze
10
- StartingOf = { message: ['--- The following addresses had delivery problems ---'] }.freeze
11
- MessagesOf = { 'userunknown' => [' User not exist', ' unknown.', '550 Unknown user ', 'No such user'] }.freeze
12
-
13
- # Parse bounce messages from McAfee Email Appliance
14
- # @param [Hash] mhead Message headers of a bounce email
15
- # @param [String] mbody Message body of a bounce email
16
- # @return [Hash] Bounce data list and message/rfc822 part
17
- # @return [Nil] it failed to parse or the arguments are missing
18
- def inquire(mhead, mbody)
19
- # X-NAI-Header: Modified by McAfee Email and Web Security Virtual Appliance
20
- return nil unless mhead['x-nai-header']
21
- return nil unless mhead['x-nai-header'].start_with?('Modified by McAfee ')
22
- return nil unless mhead['subject'] == 'Delivery Status'
23
-
24
- fieldtable = Sisimai::RFC1894.FIELDTABLE
25
- dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
26
- emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
27
- bodyslices = emailparts[0].split("\n")
28
- readslices = ['']
29
- readcursor = 0 # (Integer) Points the current cursor position
30
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
31
- issuedcode = '' # (String) Alternative diagnostic message
32
- v = nil
33
-
34
- while e = bodyslices.shift do
35
- # Read error messages and delivery status lines from the head of the email to the previous
36
- # line of the beginning of the original message.
37
- readslices << e # Save the current line for the next loop
38
-
39
- if readcursor == 0
40
- # Beginning of the bounce message or delivery status part
41
- readcursor |= Indicators[:deliverystatus] if e.include?(StartingOf[:message][0])
42
- next
43
- end
44
- next if (readcursor & Indicators[:deliverystatus]) == 0
45
- next if e.empty?
46
-
47
- # Content-Type: text/plain; name="deliveryproblems.txt"
48
- #
49
- # --- The following addresses had delivery problems ---
50
- #
51
- # <user@example.com> (User unknown user@example.com)
52
- #
53
- # --------------Boundary-00=_00000000000000000000
54
- # Content-Type: message/delivery-status; name="deliverystatus.txt"
55
- #
56
- v = dscontents[-1]
57
-
58
- if Sisimai::String.aligned(e, ['<', '@', '>', '(', ')'])
59
- # <kijitora@example.co.jp> (Unknown user kijitora@example.co.jp)
60
- if v['recipient']
61
- # There are multiple recipient addresses in the message body.
62
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
63
- v = dscontents[-1]
64
- end
65
- v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.index('>')])
66
- issuedcode = e[e.index('(') + 1, e.size]
67
- recipients += 1
68
-
69
- elsif f = Sisimai::RFC1894.match(e)
70
- # "e" matched with any field defined in RFC3464
71
- o = Sisimai::RFC1894.field(e)
72
- unless o
73
- # Fallback code for empty value or invalid formatted value
74
- # - Original-Recipient: <kijitora@example.co.jp>
75
- if e.start_with?('Original-Recipient: ')
76
- v['alias'] = Sisimai::Address.s3s4(e[e.index(':') + 1, e.size])
77
- end
78
- next
79
- end
80
- next unless fieldtable[o[0]]
81
- v[fieldtable[o[0]]] = o[2]
82
-
83
- else
84
- # Continued line of the value of Diagnostic-Code field
85
- next unless readslices[-2].start_with?('Diagnostic-Code:')
86
- next unless e.start_with?(' ')
87
- v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
88
- readslices[-1] = 'Diagnostic-Code: ' << e
89
- end
90
- end
91
- return nil unless recipients > 0
92
-
93
- dscontents.each do |e|
94
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode)
95
- MessagesOf.each_key do |r|
96
- # Verify each regular expression of session errors
97
- next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
98
- e['reason'] = r
99
- break
100
- end
101
- end
102
-
103
- return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
104
- end
105
- def description; return 'McAfee Email Appliance'; end
106
- end
107
- end
108
- end
109
-
@@ -1,119 +0,0 @@
1
- module Sisimai::Lhost
2
- # Sisimai::Lhost::MessageLabs parses a bounce email which created by Symantec.cloud: formerly MessageLabs.
3
- # Methods in the module are called from only Sisimai::Message.
4
- module MessageLabs
5
- class << self
6
- require 'sisimai/lhost'
7
-
8
- Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['Content-Type: text/rfc822-headers'].freeze
10
- StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
11
- MessagesOf = {
12
- 'userunknown' => ['542 ', ' Rejected', 'No such user'],
13
- 'securityerror' => ['Please turn on SMTP Authentication in your mail client'],
14
- }.freeze
15
-
16
- # Parse bounce messages from Symantec.cloud(MessageLabs)
17
- # @param [Hash] mhead Message headers of a bounce email
18
- # @param [String] mbody Message body of a bounce email
19
- # @return [Hash] Bounce data list and message/rfc822 part
20
- # @return [Nil] it failed to parse or the arguments are missing
21
- def inquire(mhead, mbody)
22
- # X-Msg-Ref: server-11.tower-143.messagelabs.com!1419367175!36473369!1
23
- # X-Originating-IP: [10.245.230.38]
24
- # X-StarScan-Received:
25
- # X-StarScan-Version: 6.12.5; banners=-,-,-
26
- # X-VirusChecked: Checked
27
- return nil unless mhead['x-msg-ref']
28
- return nil unless mhead['from'].include?('MAILER-DAEMON@messagelabs.com')
29
- return nil unless mhead['subject'].start_with?('Mail Delivery Failure')
30
-
31
- fieldtable = Sisimai::RFC1894.FIELDTABLE
32
- permessage = {} # (Hash) Store values of each Per-Message field
33
-
34
- dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
35
- emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
36
- bodyslices = emailparts[0].split("\n")
37
- readslices = ['']
38
- readcursor = 0 # (Integer) Points the current cursor position
39
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
40
- commandset = [] # (Array) ``in reply to * command'' list
41
- v = nil
42
-
43
- while e = bodyslices.shift do
44
- # Read error messages and delivery status lines from the head of the email to the previous
45
- # line of the beginning of the original message.
46
- readslices << e # Save the current line for the next loop
47
-
48
- if readcursor == 0
49
- # Beginning of the bounce message or message/delivery-status part
50
- readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
51
- next
52
- end
53
- next if (readcursor & Indicators[:deliverystatus]) == 0
54
- next if e.empty?
55
-
56
- if f = Sisimai::RFC1894.match(e)
57
- # "e" matched with any field defined in RFC3464
58
- next unless o = Sisimai::RFC1894.field(e)
59
- v = dscontents[-1]
60
-
61
- if o[-1] == 'addr'
62
- # Final-Recipient: rfc822; kijitora@example.jp
63
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
64
- if o[0] == 'final-recipient'
65
- # Final-Recipient: rfc822; kijitora@example.jp
66
- if v['recipient']
67
- # There are multiple recipient addresses in the message body.
68
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
69
- v = dscontents[-1]
70
- end
71
- v['recipient'] = o[2]
72
- recipients += 1
73
- else
74
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
75
- v['alias'] = o[2]
76
- end
77
- elsif o[-1] == 'code'
78
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
79
- v['spec'] = o[1]
80
- v['diagnosis'] = o[2]
81
- else
82
- # Other DSN fields defined in RFC3464
83
- next unless fieldtable[o[0]]
84
- v[fieldtable[o[0]]] = o[2]
85
-
86
- next unless f
87
- permessage[fieldtable[o[0]]] = o[2]
88
- end
89
- else
90
- # Continued line of the value of Diagnostic-Code field
91
- next unless readslices[-2].start_with?('Diagnostic-Code:')
92
- next unless e.start_with?(' ')
93
- v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
94
- readslices[-1] = 'Diagnostic-Code: ' << e
95
- end
96
- end
97
- return nil unless recipients > 0
98
-
99
- dscontents.each do |e|
100
- # Set default values if each value is empty.
101
- permessage.each_key { |a| e[a] ||= permessage[a] || '' }
102
- e['command'] = commandset.shift || ''
103
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
104
-
105
- MessagesOf.each_key do |r|
106
- # Verify each regular expression of session errors
107
- next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
108
- e['reason'] = r
109
- break
110
- end
111
- end
112
-
113
- return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
114
- end
115
- def description; return 'Symantec.cloud http://www.messagelabs.com'; end
116
- end
117
- end
118
- end
119
-
@@ -1,198 +0,0 @@
1
- module Sisimai::Lhost
2
- # Sisimai::Lhost::MXLogic parses a bounce email which created by McAfee SaaS (formerly MX Logic).
3
- # Methods in the module are called from only Sisimai::Message.
4
- module MXLogic
5
- class << self
6
- # Based on Sisimai::Lhost::Exim
7
- require 'sisimai/lhost'
8
-
9
- Indicators = Sisimai::Lhost.INDICATORS
10
- Boundaries = ['Included is a copy of the message header:'].freeze
11
- StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
12
- ReCommands = [
13
- %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
14
- %r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
15
- ].freeze
16
- MessagesOf = {
17
- # % find exim/ -type f -exec grep 'message = US' {} /dev/null \;
18
- # route.c:1158| DEBUG(D_uid) debug_printf("getpwnam() returned NULL (user not found)\n");
19
- 'userunknown' => ['user not found'],
20
- # transports/smtp.c:3524| addr->message = US"all host address lookups failed permanently";
21
- # routers/dnslookup.c:331| addr->message = US"all relevant MX records point to non-existent hosts";
22
- # route.c:1826| uschar *message = US"Unrouteable address";
23
- 'hostunknown' => [
24
- 'all host address lookups failed permanently',
25
- 'all relevant MX records point to non-existent hosts',
26
- 'Unrouteable address',
27
- ],
28
- # transports/appendfile.c:2567| addr->user_message = US"mailbox is full";
29
- # transports/appendfile.c:3049| addr->message = string_sprintf("mailbox is full "
30
- # transports/appendfile.c:3050| "(quota exceeded while writing to file %s)", filename);
31
- 'mailboxfull' => ['mailbox is full', 'error: quota exceed'],
32
- # routers/dnslookup.c:328| addr->message = US"an MX or SRV record indicated no SMTP service";
33
- # transports/smtp.c:3502| addr->message = US"no host found for existing SMTP connection";
34
- 'notaccept' => [
35
- 'an MX or SRV record indicated no SMTP service',
36
- 'no host found for existing SMTP connection',
37
- ],
38
- # parser.c:666| *errorptr = string_sprintf("%s (expected word or \"<\")", *errorptr);
39
- # parser.c:701| if(bracket_count++ > 5) FAILED(US"angle-brackets nested too deep");
40
- # parser.c:738| FAILED(US"domain missing in source-routed address");
41
- # parser.c:747| : string_sprintf("malformed address: %.32s may not follow %.*s",
42
- 'syntaxerror' => [
43
- 'angle-brackets nested too deep',
44
- 'expected word or "<"',
45
- 'domain missing in source-routed address',
46
- 'malformed address:',
47
- ],
48
- # deliver.c:5614| addr->message = US"delivery to file forbidden";
49
- # deliver.c:5624| addr->message = US"delivery to pipe forbidden";
50
- # transports/pipe.c:1156| addr->user_message = US"local delivery failed";
51
- 'systemerror' => [
52
- 'delivery to file forbidden',
53
- 'delivery to pipe forbidden',
54
- 'local delivery failed',
55
- 'LMTP error after ',
56
- ],
57
- # deliver.c:5425| new->message = US"Too many \"Received\" headers - suspected mail loop";
58
- 'contenterror' => ['Too many "Received" headers'],
59
- }.freeze
60
- DelayedFor = [
61
- 'retry timeout exceeded',
62
- 'No action is required on your part',
63
- 'retry time not reached for any host after a long failure period',
64
- 'all hosts have been failing for a long time and were last tried',
65
- 'Delay reason: ',
66
- 'has been frozen',
67
- 'was frozen on arrival by ',
68
- ].freeze
69
-
70
- # Parse bounce messages from MXLogic
71
- # @param [Hash] mhead Message headers of a bounce email
72
- # @param [String] mbody Message body of a bounce email
73
- # @return [Hash] Bounce data list and message/rfc822 part
74
- # @return [Nil] it failed to parse or the arguments are missing
75
- def inquire(mhead, mbody)
76
- # X-MX-Bounce: mta/src/queue/bounce
77
- # X-MXL-NoteHash: ffffffffffffffff-0000000000000000000000000000000000000000
78
- # X-MXL-Hash: 4c9d4d411993da17-bbd4212b6c887f6c23bab7db4bd87ef5edc00758
79
- match = 0
80
- match += 1 if mhead['x-mx-bounce']
81
- match += 1 if mhead['x-mxl-hash']
82
- match += 1 if mhead['x-mxl-notehash']
83
- match += 1 if mhead['from'].start_with?('Mail Delivery System')
84
- match += 1 if ['Delivery Status Notification', 'Mail delivery failed', 'Warning: message '].any? { |a| mhead['subject'].include?(a) }
85
- return nil unless match > 0
86
-
87
- dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
88
- emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
89
- bodyslices = emailparts[0].split("\n")
90
- readcursor = 0 # (Integer) Points the current cursor position
91
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
92
- v = nil
93
-
94
- while e = bodyslices.shift do
95
- # Read error messages and delivery status lines from the head of the email to the previous
96
- # line of the beginning of the original message.
97
- if readcursor == 0
98
- # Beginning of the bounce message or delivery status part
99
- readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
100
- next
101
- end
102
- next if (readcursor & Indicators[:deliverystatus]) == 0
103
- next if e.empty?
104
-
105
- # This message was created automatically by mail delivery software.
106
- #
107
- # A message that you sent could not be delivered to one or more of its
108
- # recipients. This is a permanent error. The following address(es) failed:
109
- #
110
- # kijitora@example.jp
111
- # SMTP error from remote mail server after RCPT TO:<kijitora@example.jp>:
112
- # host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
113
- v = dscontents[-1]
114
-
115
- if e.start_with?(' <') && e.include?('@') && e.include?('>:')
116
- # A message that you have sent could not be delivered to one or more
117
- # recipients. This is a permanent error. The following address failed:
118
- #
119
- # <kijitora@example.co.jp>: 550 5.1.1 ...
120
- if v['recipient']
121
- # There are multiple recipient addresses in the message body.
122
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
123
- v = dscontents[-1]
124
- end
125
- v['recipient'] = e[3, e.index('>:') - 3]
126
- v['diagnosis'] = e[e.index('>:') + 3, e.size]
127
- recipients += 1
128
-
129
- elsif dscontents.size == recipients
130
- # Error message
131
- next if e.empty?
132
- v['diagnosis'] << e + ' '
133
- end
134
- end
135
- return nil unless recipients > 0
136
-
137
- # Get the name of the local MTA
138
- # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
139
- receivedby = mhead['received'] || []
140
- recvdtoken = Sisimai::RFC5322.received(receivedby[-1])
141
-
142
- dscontents.each do |e|
143
- # Check the error message, the rhost, the lhost, and the smtp command.
144
- e['lhost'] = recvdtoken[0]
145
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].gsub(/[-]{2}.*\z/, ''))
146
-
147
- unless e['rhost']
148
- # Get the remote host name
149
- p1 = e['diagnosis'].index('host ') || -1
150
- p2 = e['diagnosis'].index(' ', p1 + 5)
151
-
152
- # host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
153
- e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
154
- e['rhost'] ||= recvdtoken[1]
155
- end
156
-
157
- unless e['command']
158
- # Get the SMTP command name for the session
159
- ReCommands.each do |r|
160
- # Verify each regular expression of SMTP commands
161
- if cv = e['diagnosis'].match(r)
162
- e['command'] = cv[1].upcase
163
- break
164
- end
165
- end
166
-
167
- # Detect the reason of bounce
168
- if e['command'] == 'MAIL'
169
- # MAIL | Connected to 192.0.2.135 but sender was rejected.
170
- e['reason'] = 'rejected'
171
-
172
- elsif %w[HELO EHLO].index(e['command'])
173
- # HELO | Connected to 192.0.2.135 but my name was rejected.
174
- e['reason'] = 'blocked'
175
- else
176
- # Verify each regular expression of session errors
177
- MessagesOf.each_key do |r|
178
- # Check each regular expression
179
- next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
180
- e['reason'] = r
181
- break
182
- end
183
-
184
- unless e['reason']
185
- # The reason "expired"
186
- e['reason'] = 'expired' if DelayedFor.any? { |a| e['diagnosis'].include?(a) }
187
- end
188
- end
189
- end
190
- end
191
-
192
- return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
193
- end
194
- def description; return 'McAfee SaaS'; end
195
- end
196
- end
197
- end
198
-
@@ -1,252 +0,0 @@
1
- module Sisimai::Lhost
2
- # Sisimai::Lhost::Office365 parses a bounce email which created by Microsoft Office 365. Methods in
3
- # the module are called from only Sisimai::Message.
4
- module Office365
5
- class << self
6
- require 'sisimai/lhost'
7
-
8
- Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['Content-Type: message/rfc822', 'Original message headers:'].freeze
10
- StartingOf = {
11
- error: ['Diagnostic information for administrators:'],
12
- eoerr: ['Original message headers:'],
13
- }.freeze
14
- MarkingsOf = {
15
- eoe: %r{\A(?:
16
- Original[ ][Mm]essage[ ][Hh]eaders:?
17
- |Message[ ]Hops
18
- |Cabe.+alhos[ ]originais[ ]da[ ]mensagem:
19
- |Oorspronkelijke[ ]berichtkoppen:
20
- )
21
- }x,
22
- rfc3464: %r|\AContent-Type:[ ]message/delivery-status|,
23
- lhost: %r{\A(?:
24
- Generating[ ]server
25
- |Bronserver
26
- |Servidor[ ]de[ ]origem
27
- ):[ ](.+)\z
28
- }x,
29
- error: %r{\A(?:
30
- Diagnostic[ ]information[ ]for[ ]administrators:
31
- |Error[ ]Details
32
- |Diagnostische[ ]gegevens[ ]voor[ ]beheerders:
33
- |Informa.+es[ ]de[ ]diagn.+stico[ ]para[ ]administradores:
34
- )
35
- }x,
36
- message: %r{\A(?:
37
- Delivery[ ]has[ ]failed[ ]to[ ]these[ ]recipients[ ]or[ ]groups:
38
- |Original[ ]Message[ ]Details
39
- |.+[ ]rejected[ ]your[ ]message[ ]to[ ]the[ ]following[ ]e[-]?mail[ ]addresses:
40
- |Falha[ ]na[ ]entrega[ ]a[ ]estes[ ]destinat.+rios[ ]ou[ ]grupos:
41
- |Uw[ ]bericht[ ]kan[ ]niet[ ]worden[ ]bezorgd[ ]bij[ ]de[ ]volgende[ ]geadresseerden[ ]of[ ]groepen:
42
- )
43
- }x,
44
- }.freeze
45
- Headers365 = %w[
46
- x-ms-exchange-message-is-ndr
47
- x-microsoft-antispam-prvs
48
- x-exchange-antispam-report-test
49
- x-exchange-antispam-report-cfa-test
50
- x-ms-exchange-crosstenant-originalarrivaltime
51
- x-ms-exchange-crosstenant-fromentityheader
52
- x-ms-exchange-transport-crosstenantheadersstamped
53
- ]
54
- StatusList = {
55
- # https://support.office.com/en-us/article/Email-non-delivery-reports-in-Office-365-51daa6b9-2e35-49c4-a0c9-df85bf8533c3
56
- %r/\A4[.]4[.]7\z/ => 'expired',
57
- %r/\A4[.]4[.]312\z/ => 'networkerror',
58
- %r/\A4[.]4[.]316\z/ => 'expired',
59
- %r/\A4[.]7[.]26\z/ => 'authfailure',
60
- %r/\A4[.]7[.][56]\d\d\z/ => 'blocked',
61
- %r/\A4[.]7[.]8[5-9]\d\z/ => 'blocked',
62
- %r/\A5[.]0[.]350\z/ => 'contenterror',
63
- %r/\A5[.]1[.]10\z/ => 'userunknown',
64
- %r/\A5[.]4[.]1\z/ => 'norelaying',
65
- %r/\A5[.]4[.]312\z/ => 'networkerror',
66
- %r/\A5[.]4[.]316\z/ => 'expired',
67
- %r/\A5[.]4[.]6\z/ => 'networkerror',
68
- %r/\A5[.]6[.]11\z/ => 'contenterror',
69
- %r/\A5[.]7[.]1\z/ => 'rejected',
70
- %r/\A5[.]7[.]1[23]\z/ => 'rejected',
71
- %r/\A5[.]7[.]124\z/ => 'rejected',
72
- %r/\A5[.]7[.]13[3-6]\z/ => 'rejected',
73
- %r/\A5[.]7[.]23\z/ => 'authfailure',
74
- %r/\A5[.]7[.]25\z/ => 'networkerror',
75
- %r/\A5[.]7[.]50[1-3]\z/ => 'spamdetected',
76
- %r/\A5[.]7[.]50[4-5]\z/ => 'filtered',
77
- %r/\A5[.]7[.]50[6-7]\z/ => 'blocked',
78
- %r/\A5[.]7[.]508\z/ => 'toomanyconn',
79
- %r/\A5[.]7[.]509\z/ => 'authfailure',
80
- %r/\A5[.]7[.]510\z/ => 'notaccept',
81
- %r/\A5[.]7[.]511\z/ => 'rejected',
82
- %r/\A5[.]7[.]512\z/ => 'authfailure',
83
- %r/\A5[.]7[.]57\z/ => 'securityerror',
84
- %r/\A5[.]7[.]60[6-9]\z/ => 'blocked',
85
- %r/\A5[.]7[.]6[1-4]\d\z/ => 'blocked',
86
- %r/\A5[.]7[.]7[0-4]\d\z/ => 'toomanyconn',
87
- }.freeze
88
- ReCommands = {
89
- RCPT: %r/unknown recipient or mailbox unavailable ->.+[<]?.+[@].+[.][a-zA-Z]+[>]?/,
90
- }.freeze
91
-
92
- # Parse bounce messages from Microsoft Office 365
93
- # @param [Hash] mhead Message headers of a bounce email
94
- # @param [String] mbody Message body of a bounce email
95
- # @return [Hash] Bounce data list and message/rfc822 part
96
- # @return [Nil] it failed to parse or the arguments are missing
97
- def inquire(mhead, mbody)
98
- # X-MS-Exchange-Message-Is-Ndr:
99
- # X-Microsoft-Antispam-PRVS: <....@...outlook.com>
100
- # X-Exchange-Antispam-Report-Test: UriScan:;
101
- # X-Exchange-Antispam-Report-CFA-Test:
102
- # X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Apr 2015 23:34:45.6789 (JST)
103
- # X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted
104
- # X-MS-Exchange-Transport-CrossTenantHeadersStamped: ...
105
- tryto = %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/
106
- match = 0
107
- match += 1 if mhead['subject'].include?('Undeliverable:')
108
- match += 1 if mhead['subject'].include?('Onbestelbaar:')
109
- match += 1 if mhead['subject'].include?('Não_entregue:')
110
-
111
- Headers365.each do |e|
112
- next if mhead[e].nil?
113
- next if mhead[e].empty?
114
- match += 1
115
- end
116
- match += 1 if mhead['received'].any? { |a| a =~ tryto }
117
- if mhead['message-id']
118
- # Message-ID: <00000000-0000-0000-0000-000000000000@*.*.prod.outlook.com>
119
- match += 1 if mhead['message-id'] =~ tryto
120
- end
121
- return nil if match < 2
122
-
123
- require 'sisimai/rfc1894'
124
- fieldtable = Sisimai::RFC1894.FIELDTABLE
125
- permessage = {} # (Hash) Store values of each Per-Message field
126
- dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
127
- emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
128
- bodyslices = emailparts[0].split("\n")
129
- readcursor = 0 # (Integer) Points the current cursor position
130
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
131
- connheader = {}
132
- endoferror = false # (Boolean) Flag for the end of error messages
133
- htmlbegins = false # (Boolean) Flag for HTML part
134
- v = nil
135
-
136
- while e = bodyslices.shift do
137
- # Read error messages and delivery status lines from the head of the email to the previous
138
- # line of the beginning of the original message.
139
- if readcursor == 0
140
- # Beginning of the bounce message or delivery status part
141
- readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
142
- next
143
- end
144
- next if (readcursor & Indicators[:deliverystatus]) == 0
145
- next if e.empty?
146
-
147
- # kijitora@example.com<mailto:kijitora@example.com>
148
- # The email address wasn't found at the destination domain. It might
149
- # be misspelled or it might not exist any longer. Try retyping the
150
- # address and resending the message.
151
- #
152
- # Original Message Details
153
- # Created Date: 4/29/2017 6:40:30 AM
154
- # Sender Address: neko@example.jp
155
- # Recipient Address: kijitora@example.org
156
- # Subject: Nyaan#
157
- v = dscontents[-1]
158
-
159
- if cv = e.match(/\A.+[@].+[<]mailto:(.+[@].+)[>]\z/) ||
160
- e.match(/\ARecipient[ ]Address:[ ]+(.+)\z/)
161
- # kijitora@example.com<mailto:kijitora@example.com>
162
- if v['recipient']
163
- # There are multiple recipient addresses in the message body.
164
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
165
- v = dscontents[-1]
166
- end
167
- v['recipient'] = cv[1]
168
- recipients += 1
169
-
170
- elsif cv = e.match(MarkingsOf[:lhost])
171
- # Generating server: FFFFFFFFFFFF.e0.prod.outlook.com
172
- connheader['lhost'] = cv[1].downcase
173
- else
174
- if endoferror
175
- # After "Original message headers:"
176
- next unless f = Sisimai::RFC1894.match(e)
177
- next unless o = Sisimai::RFC1894.field(e)
178
- next unless fieldtable[o[0]]
179
-
180
- if v['diagnosis']
181
- # Do not capture "Diagnostic-Code:" field because error message have already
182
- # been captured
183
- next if o[0] =~ /\A(?:diagnostic-code|final-recipient)\z/
184
- v[fieldtable[o[0]]] = o[2]
185
-
186
- next unless f
187
- permessage[fieldtable[o[0]]] = o[2]
188
- else
189
- # Capture "Diagnostic-Code:" field because no error messages have been captured
190
- v[fieldtable[o[0]]] = o[2]
191
- permessage[fieldtable[o[0]]] = o[2]
192
- end
193
- else
194
- if e =~ MarkingsOf[:error]
195
- # Diagnostic information for administrators:
196
- v['diagnosis'] = e
197
- else
198
- # kijitora@example.com
199
- # Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipien=
200
- # t not found by SMTP address lookup'
201
- if v['diagnosis']
202
- # The error message text have already captured
203
- if e =~ MarkingsOf[:eoe]
204
- # Original message headers:
205
- endoferror = true
206
- next
207
- end
208
- v['diagnosis'] << ' ' << e
209
- else
210
- # The error message text has not been captured yet
211
- endoferror = true if e =~ MarkingsOf[:rfc3464]
212
- end
213
- end
214
- end
215
- end
216
- end
217
- return nil unless recipients > 0
218
-
219
- dscontents.each do |e|
220
- # Set default values if each value is empty.
221
- permessage.each_key { |a| e[a] ||= permessage[a] || '' }
222
-
223
- e['status'] ||= ''
224
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
225
- if e['status'].empty? || e['status'].end_with?('.0.0')
226
- # There is no value of Status header or the value is 5.0.0, 4.0.0
227
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || e['status']
228
- end
229
-
230
- ReCommands.each_key do |p|
231
- # Try to match with regular expressions defined in ReCommands
232
- next unless e['diagnosis'] =~ ReCommands[p]
233
- e['command'] = p.to_s
234
- break
235
- end
236
- next unless e['status']
237
-
238
- StatusList.each_key do |f|
239
- # Try to match with each key as a regular expression
240
- next unless e['status'] =~ f
241
- e['reason'] = StatusList[f]
242
- break
243
- end
244
- end
245
-
246
- return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
247
- end
248
- def description; return 'Microsoft Office 365: https://office.microsoft.com/'; end
249
- end
250
- end
251
- end
252
-