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,66 +1,127 @@
1
1
  module Sisimai
2
2
  module Rhost
3
3
  # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
- # of get() method when the value of "destination" of the object is "charter.net". This class is
4
+ # of find() method when the value of "destination" of the object is "charter.net". This class is
5
5
  # called only Sisimai::Fact class.
6
6
  module Spectrum
7
7
  class << self
8
- ErrorCodes = {
8
+ ErrorCodes = [
9
9
  # https://www.spectrumbusiness.net/support/internet/understanding-email-error-codes
10
10
  # Error codes are placed in one of two categories: incoming or outgoing.
11
- # 1. If you are trying to send an email to a Charter email address from a non-Charter email
12
- # address (such as Gmail, Yahoo, Hotmail, etc.), you may receive an error that begins
13
- # with AUP#I, followed by four numbers.
11
+ # 1. If you're trying to send an email to a Charter email address from
12
+ # a non-Charter email address (such as Gmail, Yahoo, Hotmail, etc.),
13
+ # you may receive an error that begins with AUP#I, followed by four numbers.
14
14
  #
15
- # 2. If you are trying to send an email from a Charter email address to an outgoing recipient,
16
- # you may get an error code beginning with AUP#O, also followed by four numbers.
15
+ # 2. If you are trying to send an email from a Charter email address
16
+ # to an outgoing recipient, you may get an error code beginning with
17
+ # AUP#O, also followed by four numbers.
17
18
  #
18
- 1000 => 'blocked', # Your IP address has been blocked due to suspicious activity.
19
- 1010 => 'rejected', # This email account has been blocked from sending emails due to suspicious activity.
20
- 1090 => 'systemerror', # The email you're trying to send can't be processed. Try sending again at a later time.
21
- 1260 => 'networkerror', # Spectrum doesn't process IPV6 addresses. Connect with an IPv4 address and try again.
22
- 1500 => 'rejected', # Your email was rejected for attempting to send as a different email address than you signed in under.
23
- 1520 => 'rejected', # Your email was rejected for attempting to send as a different email address than a domain that we host.
24
- 1530 => 'mesgtoobig', # Your email was rejected because it's larger than the maximum size of 20MB.
25
- 1540 => 'toomanyconn', # Your emails were deferred for attempting to send too many in a single session.
26
- 1550 => 'toomanyconn', # Your email was rejected for having too many recipients in one message.
27
- 1560 => 'policyviolation', # Your email was rejected for having too many invalid recipients.
28
- }.freeze
29
- CodeRanges = [
30
- [1020, 1080, 'rejected'], # This email account has limited access to send emails based on suspicious activity.
31
- [1100, 1150, 'blocked'], # The IP address you're trying to connect from has an issue with the Domain Name System.
32
- [1160, 1190, 'policyviolation'], # The email you tried to send goes against your domain's security policies.
33
- [1200, 1210, 'blocked'], # The IP address you're trying to send from has been flagged by Cloudmark CSI as potential spam.
34
- [1220, 1250, 'blokced'], # Your IP address has been blacklisted by Spamhaus.
35
- [1300, 1340, 'toomanyconn'], # Spectrum limits the number of concurrent connections from a sender
36
- [1350, 1490, 'toomanyconn'], # Spectrum limits emails by the number of messages sent, amount of recipients,...
19
+ # 1000 Your IP address has been blocked due to suspicious activity. If you're a Spectrum
20
+ # customer using a Spectrum-issued IP, contact us. If you're using an IP address
21
+ # other than one provided by Spectrum, blocks will remain in place until they expire.
22
+ [1000, 0, 'blocked'],
23
+
24
+ # 1010 This email account has been blocked from sending emails due to suspicious activity.
25
+ # Blocks will expire based on the nature of the activity. If you're a Spectrum customer,
26
+ # change all of your Spectrum passwords to secure your account and then contact us.
27
+ [1010, 0, 'rejected'],
28
+
29
+ # 1020 This email account has limited access to send emails based on suspicious activity.
30
+ # 1080 Blocks will expire based on the nature of the activity.
31
+ # If you're a Spectrum customer, contact us to remove the block.
32
+ [1020, 1080, 'rejected'],
33
+
34
+ # 1090 The email you're trying to send can't be processed. Try sending again at a later time.
35
+ [1090, 0, 'systemerror'],
36
+
37
+ # 1100 The IP address you're trying to connect from has an issue with the Domain Name System.
38
+ # 1150 Spectrum requires a full circle DNS for emails to be allowed through. Verify the IP
39
+ # you're connecting from, and check the IP address to ensure a reverse DNS entry exists
40
+ # for the IP. If the IP address is a Spectrum-provided email address, contact us.
41
+ [1100, 1150, 'requireptr'],
42
+
43
+ # 1160 The email you tried to send goes against your domain's security policies.
44
+ # 1190 Please contact the email administrators of your domain.
45
+ [1160, 1190, 'policyviolation'],
46
+
47
+ # 1200 The IP address you're trying to send from has been flagged by Cloudmark CSI as
48
+ # 1210 potential spam. Have your IP administrator request a reset.
49
+ # Note: Cloudmark has sole discretion whether to remove the sending IP address from
50
+ # their lists.
51
+ [1200, 1210, 'blocked'],
52
+
53
+ # 1220 Your IP address has been blacklisted by Spamhaus. The owner of the IP address must
54
+ # 1250 contact Spamhaus to be removed from the list.
55
+ # Note: Spamhaus has sole discretion whether to remove the sending IP address from
56
+ # their lists.
57
+ [1220, 1250, 'blokced'],
58
+
59
+ # 1260 Spectrum doesn't process IPV6 addresses. Connect with an IPv4 address and try again.
60
+ [1260, 0, 'networkerror'],
61
+
62
+ # 1300 Spectrum limits the number of concurrent connections from a sender, as well as the
63
+ # 1340 total number of connections allowed. Limits vary based on the reputation of the IP
64
+ # address. Reduce your number of connections and try again later.
65
+ [1300, 1340, 'toomanyconn'],
66
+
67
+ # 1350 Spectrum limits emails by the number of messages sent, amount of recipients,
68
+ # 1490 potential for spam and invalid recipients.
69
+ [1350, 1490, 'speeding'],
70
+
71
+ # 1500 Your email was rejected for attempting to send as a different email address than you
72
+ # signed in under. Check that you're sending emails from the address you signed in with.
73
+ [1500, 0, 'rejected'],
74
+
75
+ # 1520 Your email was rejected for attempting to send as a different email address than a
76
+ # domain that we host. Check the outgoing email address and try again.
77
+ [1520, 0, 'rejected'],
78
+
79
+ # 1530 Your email was rejected because it's larger than the maximum size of 20MB.
80
+ [1530, 0, 'mesgtoobig'],
81
+
82
+ # 1540 Your emails were deferred for attempting to send too many in a single session.
83
+ # Reconnect and try reducing the number of emails you send at one time.
84
+ [1540, 0, 'speeding'],
85
+
86
+ # 1550 Your email was rejected for having too many recipients in one message. Reduce the
87
+ # number of recipients and try again later.
88
+ [1550, 0, 'speeding'],
89
+
90
+ # 1560 Your email was rejected for having too many invalid recipients. Check your outgoing
91
+ # email addresses and try again later.
92
+ [1560, 0, 'policyviolation'],
93
+
94
+ # 1580 You've tried to send messages to too many recipients in a short period of time.
95
+ # Wait a little while and try again later.
96
+ [1580, 0, 'speeding'],
37
97
  ].freeze
38
98
 
39
99
  # Detect bounce reason from https://www.spectrum.com/
40
- # @param [Sisimai::Fact] argvs Parsed email object
100
+ # @param [Sisimai::Fact] argvs Decoded email object
41
101
  # @return [String, Nil] The bounce reason at Spectrum
42
102
  # @since v4.25.8
43
- def get(argvs)
44
- statusmesg = argvs['diagnosticcode']
45
- codenumber = 0
103
+ def find(argvs)
104
+ return argvs['reason'] unless argvs['reason'].empty?
105
+ issuedcode = argvs['diagnosticcode']
106
+ reasontext = ''
107
+ codenumber = if cv = issuedcode.match(/AUP#[-A-Za-z]*(\d{4})/) then cv[1].to_i else 0 end
46
108
 
47
- if cv = statusmesg.match(/AUP#[-A-Za-z]*(\d{4})/)
48
- # Capture the numeric part of the error code
49
- codenumber = cv[1].to_i
50
- end
51
- reasontext = ErrorCodes[codenumber] || ''
52
-
53
- if reasontext.empty?
54
- # The error code was not found in ErrorCodes
55
- CodeRanges.each do |e|
56
- # Check the code range
109
+ ErrorCodes.each do |e|
110
+ # Try to find an error code matches with the code in the value of $diagnosticcode
111
+ if codenumber == e[0]
112
+ # [1500, 0, 'reason'] or [1500, 1550, 'reason']
113
+ reasontext = e[2]
114
+ break
115
+ else
116
+ # Check the code number is inlcuded the range like [1500, 1550, 'reason']
117
+ next if e[1] == 0
57
118
  next if codenumber < e[0]
58
119
  next if codenumber > e[1]
120
+
59
121
  reasontext = e[2]
60
122
  break
61
123
  end
62
124
  end
63
-
64
125
  return reasontext
65
126
  end
66
127
 
@@ -1,44 +1,66 @@
1
1
  module Sisimai
2
2
  module Rhost
3
3
  # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
- # of get() method when the value of "rhost" of the object is "mx*.qq.com". This class is called
4
+ # of find() method when the value of "rhost" of the object is "mx*.qq.com". This class is called
5
5
  # only Sisimai::Fact class.
6
6
  module Tencent
7
7
  class << self
8
8
  MessagesOf = {
9
- # https://service.mail.qq.com/cgi-bin/help?id=20022
10
- 'dmarc check failed' => 'blocked',
11
- 'spf check failed' => 'blocked',
12
- 'suspected spam ip' => 'blocked',
13
- 'mail is rejected by recipients' => 'filtered',
14
- 'message too large' => 'mesgtoobig',
15
- 'mail content denied' => 'spamdetected',
16
- 'spam is embedded in the email' => 'spamdetected',
17
- 'suspected spam' => 'spamdetected',
18
- 'bad address syntax' => 'syntaxerror',
19
- 'connection denied' => 'toomanyconn',
20
- 'connection frequency limited' => 'toomanyconn',
21
- 'domain frequency limited' => 'toomanyconn',
22
- 'ip frequency limited' => 'toomanyconn',
23
- 'sender frequency limited' => 'toomanyconn',
24
- 'mailbox unavailable or access denied' => 'toomanyconn',
25
- 'mailbox not found' => 'userunknown',
9
+ 'authfailure' => [
10
+ 'spf check failed', # https://service.mail.qq.com/detail/122/72
11
+ 'dmarc check failed',
12
+ ],
13
+ 'blocked' => [
14
+ 'suspected bounce attacks', # https://service.mail.qq.com/detail/122/57
15
+ 'suspected spam ip', # https://service.mail.qq.com/detail/122/66
16
+ 'connection denied', # https://service.mail.qq.com/detail/122/170
17
+ ],
18
+ 'mesgtoobig' => [
19
+ 'message too large', # https://service.mail.qq.com/detail/122/168
20
+ ],
21
+ 'rejected' => [
22
+ 'suspected spam', # https://service.mail.qq.com/detail/122/71
23
+ 'mail is rejected by recipients', # https://service.mail.qq.com/detail/122/92
24
+ ],
25
+ 'spandetected' => [
26
+ 'spam is embedded in the email', # https://service.mail.qq.com/detail/122/59
27
+ 'mail content denied', # https://service.mail.qq.com/detail/122/171
28
+ ],
29
+ 'speeding' => [
30
+ 'mailbox unavailable or access denined', # https://service.mail.qq.com/detail/122/166
31
+ ],
32
+ 'suspend' => [
33
+ 'is a deactivated mailbox', # http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=20022&&no=1000742
34
+ ],
35
+ 'syntaxerror' => [
36
+ 'bad address syntax', # https://service.mail.qq.com/detail/122/167
37
+ ],
38
+ 'toomanyconn' => [
39
+ 'ip frequency limited', # https://service.mail.qq.com/detail/122/172
40
+ 'domain frequency limited', # https://service.mail.qq.com/detail/122/173
41
+ 'sender frequency limited', # https://service.mail.qq.com/detail/122/174
42
+ 'connection frequency limited', # https://service.mail.qq.com/detail/122/175
43
+ ],
44
+ 'userunknown' => [
45
+ 'mailbox not found', # https://service.mail.qq.com/detail/122/169
46
+ ],
26
47
  }.freeze
27
48
 
28
49
  # Detect bounce reason from Tencent QQ
29
- # @param [Sisimai::Fact] argvs Parsed email object
50
+ # @param [Sisimai::Fact] argvs Decoded email object
30
51
  # @return [String] The bounce reason at Tencent QQ
31
- def get(argvs)
52
+ def find(argvs)
32
53
  return argvs['reason'] unless argvs['reason'].empty?
33
-
34
- statusmesg = argvs['diagnosticcode'].downcase
54
+ issuedcode = argvs['diagnosticcode'].downcase
35
55
  reasontext = ''
36
56
 
37
57
  MessagesOf.each_key do |e|
38
- # Try to match the error message with message patterns defined in $MessagesOf
39
- next unless statusmesg.include?(e)
40
- reasontext = MessagesOf[e]
41
- break
58
+ MessagesOf[e].each do |f|
59
+ next unless issuedcode.include?(f)
60
+ reasontext = e
61
+ break
62
+ end
63
+ break if reasontext.size > 0
42
64
  end
43
65
  return reasontext
44
66
  end
@@ -0,0 +1,111 @@
1
+ module Sisimai
2
+ module Rhost
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
+ # of find() method when the value of "destination" of the object is "*.yahoodns.net".
5
+ # This class is called only Sisimai::Fact class.
6
+ module YahooInc
7
+ class << self
8
+ MessagesOf = {
9
+ 'authfailure' => [
10
+ # - 550 5.7.9 This mail has been blocked because the sender is unauthenticated. Yahoo
11
+ # requires all senders to authenticate with either SPF or DKIM.
12
+ 'yahoo requires all senders to authenticate with either spf or dkim',
13
+ ],
14
+ 'blocked' => [
15
+ # - 553 5.7.1 [BL21] Connections will not be accepted from 192.0.2.25,
16
+ # because the ip is in Spamhaus's list; see http://postmaster.yahoo.com/550-bl23.html
17
+ # - 553 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL;
18
+ # see http://postmaster.yahoo.com/errors/550-bl23.html [550]",
19
+ " because the ip is in spamhaus's list;",
20
+ 'not accepted from ip addresses on spamhaus xbl',
21
+ ],
22
+ 'norelaying' => [
23
+ # - 550 relaying denied for <***@yahoo.com>
24
+ 'relaying denied for ',
25
+ ],
26
+ 'notcompliantrfc' => ['headers are not rfc compliant'],
27
+ 'policyviolation' => [
28
+ # - 554 Message not allowed - [PH01] Email not accepted for policy reasons.
29
+ # Please visit https://postmaster.yahooinc.com/error-codes
30
+ # - 554 5.7.9 Message not accepted for policy reasons.
31
+ # See https://postmaster.yahooinc.com/error-codes
32
+ 'not accepted for policy reasons',
33
+ ],
34
+ 'rejected' => [
35
+ # Observed the following error message since around March 2024:
36
+ #
37
+ # - 421 4.7.0 [TSS04] Messages from 192.0.2.25 temporarily deferred due to unexpected
38
+ # volume or user complaints - 4.16.55.1;
39
+ # see https://postmaster.yahooinc.com/error-codes (in reply to MAIL FROM command))
40
+ #
41
+ # However, the same error message is returned even for domains that are considered to
42
+ # have a poor reputation without SPF, DKIM, or DMARC settings, or for other reasons.
43
+ # It seems that the error message is not as granular as Google's.
44
+ 'temporarily deferred due to unexpected volume or user complaints',
45
+
46
+ # - 451 Message temporarily deferred due to unresolvable RFC.5321 from domain.
47
+ # See https://senders.yahooinc.com/error-codes#unresolvable-from-domain
48
+ 'due to unresolvable rfc.5321 domain',
49
+
50
+ # - 553 5.7.2 [TSS09] All messages from 192.0.2.25 will be permanently deferred;
51
+ # Retrying will NOT succeed. See https://postmaster.yahooinc.com/error-codes
52
+ # - 553 5.7.2 [TSS11] All messages from 192.0.2.25 will be permanently deferred;
53
+ # Retrying will NOT succeed. See https://postmaster.yahooinc.com/error-codes
54
+ ' will be permanently deferred',
55
+ ],
56
+ 'speeding' => [
57
+ # - 450 User is receiving mail too quickly
58
+ 'user is receiving mail too quickly',
59
+ ],
60
+ 'suspend' => [
61
+ # - 554 delivery error: dd ****@yahoo.com is no longer valid.
62
+ # - 554 30 Sorry, your message to *****@aol.jp cannot be delivered.
63
+ # This mailbox is disabled (554.30)
64
+ ' is no longer valid.',
65
+ 'this mailbox is disabled',
66
+ ],
67
+ 'syntaxerror' => [
68
+ # - 501 Syntax error in parameters or arguments
69
+ 'syntax error in parameters or arguments',
70
+ ],
71
+ 'toomanyconn' => [
72
+ # - 421 Max message per connection reached, closing transmission channel
73
+ 'max message per connection reached',
74
+ ],
75
+ 'userunknown' => [
76
+ # - 554 delivery error: dd This user doesn't have a yahoo.com account (***@yahoo.com)
77
+ # - 552 1 Requested mail action aborted, mailbox not found (in reply to end of DATA command)
78
+ "dd this user doesn't have a ",
79
+ 'mailbox not found',
80
+ ],
81
+ }.freeze
82
+
83
+ # Detect bounce reason from Yahoo Inc. (*.yahoodns.net)
84
+ # @param [Sisimai::Fact] argvs Decoded email object
85
+ # @return [String] The bounce reason for YahooInc
86
+ # @see https://senders.yahooinc.com/smtp-error-codes
87
+ # https://smtpfieldmanual.com/provider/yahoo
88
+ # https://www.postmastery.com/yahoo-postmaster/
89
+ # @since v5.1.0
90
+ def find(argvs)
91
+ return argvs['reason'] unless argvs['reason'].empty?
92
+ issuedcode = argvs['diagnosticcode'].downcase
93
+ reasontext = ''
94
+
95
+ MessagesOf.each_key do |e|
96
+ MessagesOf[e].each do |f|
97
+ next unless issuedcode.include?(f)
98
+ reasontext = e
99
+ break
100
+ end
101
+ break if reasontext.size > 0
102
+ end
103
+
104
+ return reasontext
105
+ end
106
+
107
+ end
108
+ end
109
+ end
110
+ end
111
+
data/lib/sisimai/rhost.rb CHANGED
@@ -1,61 +1,84 @@
1
1
  module Sisimai
2
2
  # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
3
- # of get() method when the value of rhost of the object is listed in the results of Sisimai::Rhost
3
+ # of find() method when the value of rhost of the object is listed in the results of Sisimai::Rhost
4
4
  # ->list method. This class is called only Sisimai::Fact class.
5
5
  module Rhost
6
6
  class << self
7
7
  RhostClass = {
8
- 'Cox' => ['cox.net'],
9
- 'FrancePTT' => ['.laposte.net', '.orange.fr', '.wanadoo.fr'],
10
- 'GoDaddy' => ['smtp.secureserver.net', 'mailstore1.secureserver.net'],
11
- 'Google' => ['aspmx.l.google.com', 'gmail-smtp-in.l.google.com'],
12
- 'IUA' => ['.email.ua'],
13
- 'KDDI' => ['.ezweb.ne.jp', 'msmx.au.com'],
14
- 'Microsoft' => ['.prod.outlook.com', '.protection.outlook.com'],
15
- 'Mimecast' => ['.mimecast.com'],
16
- 'NTTDOCOMO' => ['mfsmax.docomo.ne.jp'],
17
- 'Spectrum' => ['charter.net'],
18
- 'Tencent' => ['.qq.com'],
8
+ "Aol" => [".mail.aol.com", ".mx.aol.com"],
9
+ "Apple" => [".mail.icloud.com", ".apple.com", ".me.com"],
10
+ "Cox" => ["cox.net"],
11
+ "Facebook" => [".facebook.com"],
12
+ "FrancePTT" => [".laposte.net", ".orange.fr", ".wanadoo.fr"],
13
+ "GoDaddy" => ["smtp.secureserver.net", "mailstore1.secureserver.net"],
14
+ "Google" => ["aspmx.l.google.com", "gmail-smtp-in.l.google.com"],
15
+ "GSuite" => ["googlemail.com"],
16
+ "IUA" => [".email.ua"],
17
+ "KDDI" => [".ezweb.ne.jp", "msmx.au.com"],
18
+ "MessageLabs" => [".messagelabs.com"],
19
+ "Microsoft" => [".prod.outlook.com", ".protection.outlook.com", ".onmicrosoft.com", ".exchangelabs.com"],
20
+ "Mimecast" => [".mimecast.com"],
21
+ "NTTDOCOMO" => ["mfsmax.docomo.ne.jp"],
22
+ "Outlook" => [".hotmail.com"],
23
+ "Spectrum" => ["charter.net"],
24
+ "Tencent" => [".qq.com"],
25
+ "YahooInc" => [".yahoodns.net"],
19
26
  }.freeze
20
27
 
21
- # The value of "rhost" is listed in RhostClass or not
22
- # @param [String] argvs Remote host name
23
- # @return [True,False] True: matched
24
- # False: did not match
25
- def match(rhost)
26
- return false if rhost.empty?
28
+ # Returns the rhost class name
29
+ # @param [Hash] argvs Decoded email data
30
+ # @return [String] rhost class name
31
+ def name(argvs)
32
+ return "" if argvs.nil?
27
33
 
28
- host0 = rhost.downcase
29
- match = false
30
- RhostClass.each_key do |e|
31
- # Try to match with each key of RhostClass
32
- next unless RhostClass[e].any? { |a| host0.end_with?(a) }
33
- match = true
34
- break
34
+ rhostclass = ""
35
+ clienthost = argvs["lhost"].downcase
36
+ remotehost = argvs["rhost"].downcase
37
+ domainpart = argvs["destination"].downcase
38
+
39
+ catch :FINDRHOST do
40
+ # Try to match the hostname patterns with the following order:
41
+ # 1. destination: The domain part of the recipient address
42
+ # 2. rhost: remote hostname
43
+ # 3. lhost: local MTA hostname
44
+ RhostClass.each_key do |e|
45
+ # Try to match the domain part of the recipient address with each value of RhostClass
46
+ next unless RhostClass[e].any? { |a| a.end_with?(domainpart) }
47
+ rhostclass = e
48
+ throw :FINDRHOST
49
+ end
50
+
51
+ RhostClass.each_key do |e|
52
+ # Try to match the remote host with each value of RhostClass
53
+ next unless RhostClass[e].any? { |a| remotehost.end_with?(a) }
54
+ rhostclass = e
55
+ throw :FINDRHOST
56
+ end
57
+
58
+ # Neither the remote host nor the destination did not matched with any value of RhostClass
59
+ RhostClass.each_key do |e|
60
+ # Try to match the client host with each value of RhostClass
61
+ next unless RhostClass[e].any? { |a| clienthost.end_with?(a) }
62
+ rhostclass = e
63
+ throw :FINDRHOST
64
+ end
35
65
  end
36
- return match
66
+ return rhostclass
37
67
  end
38
68
 
39
69
  # Detect the bounce reason from certain remote hosts
40
- # @param [Hash] argvs Parsed email data
41
- # @param [String] proxy The alternative of the "rhost"
70
+ # @param [Hash] argvs Decoded email data
42
71
  # @return [String] The value of bounce reason
43
- def get(argvs, proxy = nil)
44
- remotehost = proxy || argvs['rhost'].downcase
45
- rhostclass = ''
46
- modulename = ''
72
+ def find(argvs)
73
+ return "" if argvs.nil?
47
74
 
48
- RhostClass.each_key do |e|
49
- # Try to match with each key of RhostClass
50
- next unless RhostClass[e].any? { |a| remotehost.end_with?(a) }
51
- modulename = 'Sisimai::Rhost::' << e
52
- rhostclass = 'sisimai/rhost/' << e.downcase
53
- break
54
- end
55
- return nil if rhostclass.empty?
75
+ rhostclass = name(argvs); return "" if rhostclass.empty?
76
+ modulepath = "sisimai/rhost/" << rhostclass.downcase; require modulepath
77
+ modulename = "Sisimai::Rhost::" << rhostclass
56
78
 
57
- require rhostclass
58
- reasontext = Module.const_get(modulename).get(argvs)
79
+ #rhostclass = "sisimai/rhost/" << modulename.downcase.split("::")[2]; require rhostclass
80
+ reasontext = Module.const_get(modulename).find(argvs)
81
+ return "" if reasontext.empty?
59
82
  return reasontext
60
83
  end
61
84
  end
@@ -3,9 +3,14 @@ module Sisimai
3
3
  # Sisimai::SMTP::Transcript is an SMTP Command related utilities
4
4
  module Command
5
5
  class << self
6
+ Availables = [
7
+ "HELO", "EHLO", "MAIL", "RCPT", "DATA", "QUIT", "RSET", "NOOP", "VRFY", "ETRN", "EXPN",
8
+ "HELP", "AUTH", "STARTTLS", "XFORWARD",
9
+ "CONN", # CONN is a pseudo SMTP command used only in Sisimai
10
+ ].freeze
6
11
  Detectable = [
7
- 'HELO', 'EHLO', 'STARTTLS', 'AUTH PLAIN', 'AUTH LOGIN', 'AUTH CRAM-', 'AUTH DIGEST-',
8
- 'MAIL F', 'RCPT', 'RCPT T', 'DATA', 'QUIT', 'XFORWARD',
12
+ "HELO", "EHLO", "STARTTLS", "AUTH PLAIN", "AUTH LOGIN", "AUTH CRAM-", "AUTH DIGEST-",
13
+ "MAIL F", "RCPT", "RCPT T", "DATA", "QUIT", "XFORWARD",
9
14
  ].freeze
10
15
 
11
16
  # Check that an SMTP command in the argument is valid or not
@@ -13,43 +18,48 @@ module Sisimai
13
18
  # @return [Boolean] 0: Is not a valid SMTP command, 1: Is a valid SMTP command
14
19
  # @since v5.0.0
15
20
  def test(argv0 = '')
16
- return nil if argv0.empty?
17
- return nil if argv0.size < 4
18
-
19
- comm0 = %w[HELO EHLO MAIL RCPT DATA QUIT RSET NOOP VRFY ETRN EXPN HELP]
20
- comm1 = %w[AUTH STARTTLS XFORWARD]
21
- return true if comm0.any? { |a| argv0.include?(a) }
22
- return true if comm1.any? { |a| argv0.include?(a) }
23
- return true if argv0.include?('CONN') # CONN is a pseudo SMTP command used only in Sisimai
21
+ return false if argv0.nil? || argv0.empty? || argv0.size < 4
22
+ return true if Availables.any? { |a| argv0.include?(a) }
24
23
  return false
25
24
  end
26
25
 
27
26
  # Pick an SMTP command from the given string
28
27
  # @param [String] argv0 A transcript text MTA returned
29
28
  # @return [String] An SMTP command
30
- # @return [undef] Failed to find an SMTP command or the 1st argument is missing
31
29
  # @since v5.0.0
32
30
  def find(argv0 = '')
33
- return nil unless Sisimai::SMTP::Command.test(argv0)
31
+ return "" unless Sisimai::SMTP::Command.test(argv0)
34
32
 
35
- stringsize = argv0.size
36
- commandmap = { 'STAR' => 'STARTTLS', 'XFOR' => 'XFORWARD' }
33
+ issuedcode = " " + argv0.downcase + " "
34
+ commandmap = { "STAR" => "STARTTLS", "XFOR" => "XFORWARD" }
37
35
  commandset = []
38
- previouspp = 0
39
36
 
40
37
  Detectable.each do |e|
41
38
  # Find an SMTP command from the given string
42
- p0 = argv0.index(e, previouspp)
43
- next unless p0
44
- next if p0 + 4 > stringsize
45
- previouspp = p0
39
+ p0 = argv0.index(e); next unless p0
40
+ if e.include?(" ") == false
41
+ # For example, "RCPT T" does not appear in an email address or a domain name
42
+ cx = true; while true do
43
+ # Exclude an SMTP command in the part of an email address, a domain name, such as
44
+ # DATABASE@EXAMPLE.JP, EMAIL.EXAMPLE.COM, and so on.
45
+ ca = issuedcode[p0, 1].ord
46
+ cz = issuedcode[p0 + e.size + 1, 1].ord
47
+
48
+ break if ca > 47 && ca < 58 || cz > 47 && cz < 58; # 0-9
49
+ break if ca > 63 && ca < 91 || cz > 63 && cz < 91; # @-Z
50
+ break if ca > 96 && ca < 123 || cz > 96 && cz < 123; # `-z
51
+ cx = false; break
52
+ end
53
+ next if cx == true
54
+ end
46
55
 
47
- cv = argv0[p0, 4]; next if commandset.include?(cv)
56
+ # There is the same command in the "commanset" or nor
57
+ cv = e[0, 4]; next if commandset.any? { |a| cv.start_with?(a) }
48
58
  cv = commandmap[cv] if commandmap.has_key?(cv)
49
59
  commandset << cv
50
60
  end
51
61
 
52
- return nil if commandset.empty?
62
+ return "" if commandset.empty?
53
63
  return commandset.pop
54
64
  end
55
65
  end