sisimai 5.4.1-java → 5.5.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codecovio.yml +1 -1
  3. data/.github/workflows/rake-test.yml +1 -1
  4. data/ChangeLog.md +35 -0
  5. data/Makefile +2 -4
  6. data/README-JA.md +23 -20
  7. data/README.md +23 -20
  8. data/lib/sisimai/address.rb +92 -44
  9. data/lib/sisimai/arf.rb +7 -8
  10. data/lib/sisimai/datetime.rb +2 -2
  11. data/lib/sisimai/fact/json.rb +1 -2
  12. data/lib/sisimai/fact/yaml.rb +1 -2
  13. data/lib/sisimai/fact.rb +60 -35
  14. data/lib/sisimai/lda.rb +2 -2
  15. data/lib/sisimai/lhost/activehunter.rb +4 -5
  16. data/lib/sisimai/lhost/amazonses.rb +3 -4
  17. data/lib/sisimai/lhost/apachejames.rb +2 -2
  18. data/lib/sisimai/lhost/biglobe.rb +6 -6
  19. data/lib/sisimai/lhost/courier.rb +7 -7
  20. data/lib/sisimai/lhost/domino.rb +6 -6
  21. data/lib/sisimai/lhost/dragonfly.rb +5 -5
  22. data/lib/sisimai/lhost/einsundeins.rb +4 -4
  23. data/lib/sisimai/lhost/exchange2003.rb +7 -7
  24. data/lib/sisimai/lhost/exchange2007.rb +3 -3
  25. data/lib/sisimai/lhost/exim.rb +7 -7
  26. data/lib/sisimai/lhost/ezweb.rb +3 -2
  27. data/lib/sisimai/lhost/fml.rb +9 -9
  28. data/lib/sisimai/lhost/gmail.rb +9 -9
  29. data/lib/sisimai/lhost/gmx.rb +3 -3
  30. data/lib/sisimai/lhost/googlegroups.rb +6 -7
  31. data/lib/sisimai/lhost/googleworkspace.rb +5 -6
  32. data/lib/sisimai/lhost/imailserver.rb +4 -4
  33. data/lib/sisimai/lhost/kddi.rb +4 -4
  34. data/lib/sisimai/lhost/mailfoundry.rb +3 -3
  35. data/lib/sisimai/lhost/{mailmarshalsmtp.rb → mailmarshal.rb} +5 -5
  36. data/lib/sisimai/lhost/messagingserver.rb +8 -8
  37. data/lib/sisimai/lhost/mfilter.rb +8 -4
  38. data/lib/sisimai/lhost/mimecast.rb +105 -0
  39. data/lib/sisimai/lhost/notes.rb +5 -5
  40. data/lib/sisimai/lhost/opensmtpd.rb +5 -5
  41. data/lib/sisimai/lhost/postfix.rb +38 -32
  42. data/lib/sisimai/lhost/qmail.rb +6 -6
  43. data/lib/sisimai/lhost/sendmail.rb +13 -13
  44. data/lib/sisimai/lhost/{interscanmss.rb → trendmicro.rb} +8 -9
  45. data/lib/sisimai/lhost/v5sendmail.rb +7 -7
  46. data/lib/sisimai/lhost/verizon.rb +3 -3
  47. data/lib/sisimai/lhost/x1.rb +7 -4
  48. data/lib/sisimai/lhost/x2.rb +40 -12
  49. data/lib/sisimai/lhost/x3.rb +3 -3
  50. data/lib/sisimai/lhost/x6.rb +2 -2
  51. data/lib/sisimai/lhost/zoho.rb +5 -5
  52. data/lib/sisimai/lhost.rb +18 -17
  53. data/lib/sisimai/mail/maildir.rb +4 -4
  54. data/lib/sisimai/mail/mbox.rb +4 -4
  55. data/lib/sisimai/mail/memory.rb +1 -1
  56. data/lib/sisimai/mail/stdin.rb +2 -2
  57. data/lib/sisimai/message.rb +34 -34
  58. data/lib/sisimai/order.rb +5 -4
  59. data/lib/sisimai/reason/authfailure.rb +1 -1
  60. data/lib/sisimai/reason/badreputation.rb +1 -1
  61. data/lib/sisimai/reason/blocked.rb +2 -1
  62. data/lib/sisimai/reason/contenterror.rb +1 -2
  63. data/lib/sisimai/reason/exceedlimit.rb +1 -1
  64. data/lib/sisimai/reason/expired.rb +1 -1
  65. data/lib/sisimai/reason/failedstarttls.rb +1 -1
  66. data/lib/sisimai/reason/filtered.rb +1 -1
  67. data/lib/sisimai/reason/hasmoved.rb +1 -1
  68. data/lib/sisimai/reason/hostunknown.rb +2 -2
  69. data/lib/sisimai/reason/mailboxfull.rb +1 -1
  70. data/lib/sisimai/reason/mailererror.rb +1 -1
  71. data/lib/sisimai/reason/mesgtoobig.rb +1 -1
  72. data/lib/sisimai/reason/networkerror.rb +1 -1
  73. data/lib/sisimai/reason/norelaying.rb +2 -2
  74. data/lib/sisimai/reason/notaccept.rb +2 -3
  75. data/lib/sisimai/reason/notcompliantrfc.rb +1 -1
  76. data/lib/sisimai/reason/policyviolation.rb +2 -4
  77. data/lib/sisimai/reason/rejected.rb +5 -3
  78. data/lib/sisimai/reason/requireptr.rb +1 -1
  79. data/lib/sisimai/reason/securityerror.rb +1 -1
  80. data/lib/sisimai/reason/spamdetected.rb +1 -1
  81. data/lib/sisimai/reason/speeding.rb +1 -1
  82. data/lib/sisimai/reason/suspend.rb +2 -1
  83. data/lib/sisimai/reason/systemerror.rb +1 -1
  84. data/lib/sisimai/reason/systemfull.rb +1 -1
  85. data/lib/sisimai/reason/toomanyconn.rb +1 -1
  86. data/lib/sisimai/reason/userunknown.rb +4 -3
  87. data/lib/sisimai/reason/vacation.rb +1 -1
  88. data/lib/sisimai/reason/virusdetected.rb +1 -1
  89. data/lib/sisimai/reason.rb +12 -12
  90. data/lib/sisimai/rfc1123.rb +58 -18
  91. data/lib/sisimai/rfc1894.rb +6 -8
  92. data/lib/sisimai/rfc2045.rb +25 -13
  93. data/lib/sisimai/rfc3464/thirdparty.rb +2 -3
  94. data/lib/sisimai/rfc3464.rb +6 -6
  95. data/lib/sisimai/rfc3834.rb +18 -8
  96. data/lib/sisimai/rfc5322.rb +9 -9
  97. data/lib/sisimai/rfc791.rb +2 -2
  98. data/lib/sisimai/rhost/aol.rb +4 -1
  99. data/lib/sisimai/rhost/apple.rb +11 -7
  100. data/lib/sisimai/rhost/cox.rb +9 -5
  101. data/lib/sisimai/rhost/facebook.rb +9 -3
  102. data/lib/sisimai/rhost/franceptt.rb +86 -37
  103. data/lib/sisimai/rhost/godaddy.rb +10 -1
  104. data/lib/sisimai/rhost/google.rb +6 -6
  105. data/lib/sisimai/rhost/gsuite.rb +1 -1
  106. data/lib/sisimai/rhost/kddi.rb +1 -1
  107. data/lib/sisimai/rhost/messagelabs.rb +160 -2
  108. data/lib/sisimai/rhost/microsoft.rb +77 -26
  109. data/lib/sisimai/rhost/mimecast.rb +30 -21
  110. data/lib/sisimai/rhost/nttdocomo.rb +69 -89
  111. data/lib/sisimai/rhost/outlook.rb +1 -1
  112. data/lib/sisimai/rhost/spectrum.rb +1 -1
  113. data/lib/sisimai/rhost/tencent.rb +5 -4
  114. data/lib/sisimai/rhost/yahooinc.rb +2 -2
  115. data/lib/sisimai/rhost/zoho.rb +72 -0
  116. data/lib/sisimai/rhost.rb +4 -3
  117. data/lib/sisimai/smtp/command.rb +2 -2
  118. data/lib/sisimai/smtp/reply.rb +11 -4
  119. data/lib/sisimai/smtp/status.rb +17 -8
  120. data/lib/sisimai/smtp/transcript.rb +3 -3
  121. data/lib/sisimai/string.rb +6 -10
  122. data/lib/sisimai/version.rb +1 -1
  123. data/lib/sisimai.rb +1 -1
  124. data/set-of-emails/maildir/bsd/lhost-exim-56.eml +40 -40
  125. data/set-of-emails/maildir/bsd/lhost-mfilter-05.eml +41 -0
  126. data/set-of-emails/maildir/bsd/lhost-mimecast-01.eml +46 -0
  127. data/set-of-emails/maildir/bsd/lhost-mimecast-02.eml +59 -0
  128. data/set-of-emails/maildir/bsd/lhost-postfix-79.eml +81 -0
  129. data/set-of-emails/maildir/bsd/lhost-postfix-80.eml +84 -0
  130. data/set-of-emails/maildir/bsd/lhost-x1-03.eml +26 -0
  131. data/set-of-emails/maildir/bsd/lhost-x1-04.eml +45 -0
  132. data/set-of-emails/maildir/bsd/lhost-x2-07.eml +30 -0
  133. data/set-of-emails/maildir/bsd/rfc3464-66.eml +170 -0
  134. data/set-of-emails/maildir/bsd/rfc3834-06.eml +59 -0
  135. data/set-of-emails/maildir/bsd/rhost-zoho-01.eml +88 -0
  136. data/set-of-emails/maildir/bsd/rhost-zoho-02.eml +86 -0
  137. data/set-of-emails/maildir/bsd/rhost-zoho-03.eml +87 -0
  138. data/set-of-emails/maildir/bsd/rhost-zoho-04.eml +86 -0
  139. data/set-of-emails/maildir/not/rb-issue-368-bug.eml +39 -0
  140. data/sisimai-java.gemspec +1 -1
  141. data/sisimai.gemspec +1 -1
  142. metadata +26 -9
  143. /data/set-of-emails/maildir/bsd/{lhost-mailmarshalsmtp-02.eml → lhost-mailmarshal-02.eml} +0 -0
  144. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-01.eml → lhost-trendmicro-01.eml} +0 -0
  145. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-02.eml → lhost-trendmicro-02.eml} +0 -0
  146. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-03.eml → lhost-trendmicro-03.eml} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cba4e83abaecd27d45c962f33cd11b96dc97d1078353205f3c74f4b64b371c7c
4
- data.tar.gz: 07de21b8f8d55cd5153c2bc7a2189569ff55eec76c01727e798e44f8290f3d92
3
+ metadata.gz: cce493bf6db19759e2159c36d40d5278493243187083b92f35c47aea14d52ca7
4
+ data.tar.gz: 75080d90011ad6813fa681dbc1f9ff02c604cc0653f03bb7b37791f7b21187fe
5
5
  SHA512:
6
- metadata.gz: a4341e54b492a11d4a2f01d1bb2911db3459d87de40011e4d0f703faf1b0d78f4628a47163beb1977549045ffd212904ab3db15e58df193087b74ac7d8f17a27
7
- data.tar.gz: 959954d39a80f494d44b43898fa93907ca5fcabe39405ca70e2c32d75d95e5bbd02c3d1705171b67ace393ad09157834fc522fe3afa0661d9f2b46e7a40992e1
6
+ metadata.gz: 0d974c494297ca7f3200b30ca630cbd9d99f3536222fbe84a86746669da335295869c0811d017d61ad813e2be154ab5562b861bc3bdbbbe798309256ded62006
7
+ data.tar.gz: 85a40b4f2f0dda6e9bbdecee8027dcf71d81428b041d59a7522b5cf0defe701c4af1a343494b321d5fcf0399e155b4aa2116a50591d09b64851490a1d944fdaa
@@ -15,7 +15,7 @@ jobs:
15
15
  - name: Setup CRuby
16
16
  uses: ruby/setup-ruby@v1
17
17
  with:
18
- ruby-version: "3.3"
18
+ ruby-version: "3.4.7"
19
19
  - name: Install minitest
20
20
  run: gem install minitest -v 5.15.0
21
21
  - name: Install oj
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- cruby: ["2.4", "3.3", "3.4"]
14
+ cruby: ["2.5.9", "3.3.10", "3.4.7"]
15
15
  steps:
16
16
  - name: Checkout the repository(CRuby)
17
17
  uses: actions/checkout@v4
data/ChangeLog.md CHANGED
@@ -3,6 +3,41 @@ RELEASE NOTES for Ruby version of Sisimai
3
3
  - releases: "https://github.com/sisimai/rb-sisimai/releases"
4
4
  - download: "https://rubygems.org/gems/sisimai"
5
5
 
6
+ v5.5.0
7
+ ---------------------------------------------------------------------------------------------------
8
+ - release: "Fri, 5 Dec 2025 17:25:22 +0900 (JST)"
9
+ - version: "5.5.0"
10
+ - changes:
11
+ - #358 #359 Fix the file encoding of `Sisimai::Lhost::Exchange2007`: sjis => utf8
12
+ - #361 #362 Fix encoding problem (ASCII-8BIT, UTF-8) in MIME decoding. Thanks to @timoschilling
13
+ - #360 #364 Update SMTP reply codes defined in `Sisimai::SMTP::Reply.Associated`.
14
+ - #365 Implement `Sisimai::SMTP::Status.is_ambiguous` method.
15
+ - #363 Sisimai partially supports the media types described in RFC6533 such as `message/global`.
16
+ - #368 #369 Fix the index out of range bug in multipart blocks. Thanks to @timoschilling
17
+ - #367 #370 Implement `Sisimai::Lhost::Mimecast`.
18
+ - #325 #323 Remove the following accessors and JSON keys of `Sisimai::Fact` deprecated at v5.2.0.
19
+ - `smtpagent` (use `decodedby` instead)
20
+ - `smtpcommand` (use `command` instead)
21
+ - #375 #377 #378 Sisimai requires Ruby 2.5 or later.
22
+ - Add new error message pattern for Spamhaus (Blocked).
23
+ - #379 Reduce `unless` expression.
24
+ - #382 `Sisimai::Lhost::MailMarshalSMTP` has been renamed to `Sisimai::Lhost::MailMarshal`.
25
+ - #383 Update `Sisimai::RFC3834` for detecting `Suspend` reason.
26
+ - #384 #385 #386 Fix wrong reason names and typos.
27
+ - #389 Fixed bugs in `Sisimai::Address.is_emailaddress`.
28
+ - #390 Check that the decoded MIME part is a binary or not in `Sisimai::RFC2045`.
29
+ - #391 #394 Update SMTP error codes and messages in the following `Sisimai::Rhost` packages:
30
+ - `Apple` `inactive email address` indicates `Suspend`
31
+ - `Facebook` Update `AuthFailure` and `MailboxFull`
32
+ - `FrancePTT` Update `AuthFailure`, `Blocked`, `Rejected`, and `TooManyConn`
33
+ - `GoDaddy` Add `TooManyConn`
34
+ - `MessageLabs` Add many error message patterns
35
+ - `Microsoft` Implement SMTP error codes described in Outlook Postmaster/Troubleshooting
36
+ - `Tencent` Add `Speeding`
37
+ - `Zoho` Implement as a new module
38
+ - #396 Sisimai works on Ruby 3.3.10 and 3.4.7.
39
+ - #397 EXPERIMENTAL: Implement `toxic` field in the decoded results.
40
+
6
41
  v5.4.1
7
42
  ---------------------------------------------------------------------------------------------------
8
43
  - release: "Sun, 31 Aug 2025 09:22:25 +0900 (JST)"
data/Makefile CHANGED
@@ -58,12 +58,10 @@ release:
58
58
 
59
59
  test: user-test author-test
60
60
  user-test:
61
- # Suppress warning messages until v5.5.0
62
- RUBYOPT="$(RUBYARGUMENT)" rake publictest 2> /dev/null
61
+ RUBYOPT="$(RUBYARGUMENT)" rake publictest
63
62
 
64
63
  author-test:
65
- # Suppress warning messages until v5.5.0
66
- RUBYOPT="$(RUBYARGUMENT)" rake privatetest 2> /dev/null
64
+ RUBYOPT="$(RUBYARGUMENT)" rake privatetest
67
65
 
68
66
  check:
69
67
  find lib -type f -exec grep --color -E ' $$' {} /dev/null \;
data/README-JA.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ![](https://libsisimai.org/static/images/logo/sisimai-x01.png)
2
2
  [![License](https://img.shields.io/badge/license-BSD%202--Clause-orange.svg)](https://github.com/sisimai/rb-sisimai/blob/master/LICENSE)
3
- [![Ruby](https://img.shields.io/badge/ruby-v2.4.0--v3.4.0-red.svg)](https://www.ruby-lang.org/)
3
+ [![Ruby](https://img.shields.io/badge/ruby-v2.5.0--v3.4.0-red.svg)](https://www.ruby-lang.org/)
4
4
  [![Gem Version](https://badge.fury.io/rb/sisimai.svg)](https://badge.fury.io/rb/sisimai)
5
5
  [![codecov](https://codecov.io/github/sisimai/rb-sisimai/graph/badge.svg?token=YGkyluNWiZ)](https://codecov.io/github/sisimai/rb-sisimai)
6
6
 
@@ -16,7 +16,7 @@
16
16
  > 該当するバージョンをお使いの場合はv4.25.14p12以降へアップグレードしてください。**
17
17
 
18
18
  > [!WARNING]
19
- > Sisimai 5はRuby 2.4以上が必要です。インストール/アップグレードを実行する前に`ruby -v`コマンドで
19
+ > Sisimai 5はRuby 2.5以上が必要です。インストール/アップグレードを実行する前に`ruby -v`コマンドで
20
20
  > システムに入っているRubyのバージョンを確認してください。
21
21
 
22
22
  > [!NOTE]
@@ -65,7 +65,7 @@ Sisimai(シシマイ)は複雑で多種多様なバウンスメールを解析
65
65
  The key features of Sisimai
66
66
  ---------------------------------------------------------------------------------------------------
67
67
  * __バウンスメールを構造化したデータに変換__
68
- * 以下26項目の情報を含むデータ構造[^2]
68
+ * 以下27項目の情報を含むデータ構造[^2]
69
69
  * __基本的情報__: `timestamp`, `origin`
70
70
  * __発信者情報__: `addresser`, `senderdomain`,
71
71
  * __受信者情報__: `recipient`, `destination`, `alias`
@@ -83,9 +83,9 @@ The key features of Sisimai
83
83
  * `gem install`
84
84
  * `git clone && make`
85
85
  * __高い解析精度__
86
- * [73種類のMTAs/MDAs/ESPs](https://libsisimai.org/en/engine/)に対応
86
+ * [60種類のMTAs/MDAs/ESPs](https://libsisimai.org/en/engine/)に対応
87
87
  * Feedback Loop(ARF)にも対応
88
- * [34種類のバウンス理由](https://libsisimai.org/en/reason/)を検出
88
+ * [36種類のバウンス理由](https://libsisimai.org/en/reason/)を検出
89
89
 
90
90
  [^2]: コールバック機能を使用すると`catch`アクセサの下に独自のデータを追加できます
91
91
 
@@ -105,7 +105,7 @@ Sisimaiの動作環境についての詳細は[Sisimai | シシマイを使っ
105
105
  をご覧ください。
106
106
 
107
107
 
108
- * [Ruby 2.4.0 or later](http://www.ruby-lang.org/)
108
+ * [Ruby 2.5.0 or later](http://www.ruby-lang.org/)
109
109
  * [__oj | The fastest JSON parser and object serializer__](https://rubygems.org/gems/oj)
110
110
  * Also works on [JRuby 9.2 or later](http://jruby.org)
111
111
  * [__jrjackson | A mostly native JRuby wrapper for the java jackson json processor jar__](https://rubygems.org/gems/jrjackson)
@@ -115,17 +115,17 @@ Install
115
115
  ### From RubyGems.org
116
116
  ```shell
117
117
  $ sudo gem install sisimai
118
- Fetching: sisimai-5.2.0.gem (100%)
119
- Successfully installed sisimai-5.2.0
120
- Parsing documentation for sisimai-5.2.0
121
- Installing ri documentation for sisimai-5.2.0
118
+ Fetching: sisimai-5.5.0.gem (100%)
119
+ Successfully installed sisimai-5.5.0
120
+ Parsing documentation for sisimai-5.5.0
121
+ Installing ri documentation for sisimai-5.5.0
122
122
  Done installing documentation for sisimai after 6 seconds
123
123
  1 gem installed
124
124
  ```
125
125
 
126
126
  ### From GitHub
127
127
  > [!WARNING]
128
- > Sisimai 5はRuby 2.4以上が必要です。インストール/アップグレードを実行する前に`ruby -v`コマンドで
128
+ > Sisimai 5はRuby 2.5以上が必要です。インストール/アップグレードを実行する前に`ruby -v`コマンドで
129
129
  > システムに入っているRubyのバージョンを確認してください。
130
130
 
131
131
  ```shell
@@ -146,13 +146,13 @@ if [ -d "/usr/local/jr" ]; then \
146
146
  ...
147
147
  3 gems installed
148
148
  /opt/local/bin/rake install
149
- sisimai 5.2.0 built to pkg/sisimai-5.2.0.gem.
150
- sisimai (5.2.0) installed.
149
+ sisimai 5.5.0 built to pkg/sisimai-5.5.0.gem.
150
+ sisimai (5.5.0) installed.
151
151
  if [ -d "/usr/local/jr" ]; then \
152
152
  PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
153
153
  fi
154
- sisimai 5.2.0 built to pkg/sisimai-5.2.0-java.gem.
155
- sisimai (5.2.0) installed.
154
+ sisimai 5.5.0 built to pkg/sisimai-5.5.0-java.gem.
155
+ sisimai (5.5.0) installed.
156
156
  ```
157
157
 
158
158
  Usage
@@ -333,6 +333,7 @@ Output example
333
333
  "timezoneoffset": "+0900",
334
334
  "replycode": 550,
335
335
  "token": "84656774898baa90660be3e12fe0526e108d4473",
336
+ "toxic": false,
336
337
  "diagnostictype": "SMTP",
337
338
  "timestamp": 1650119685,
338
339
  "diagnosticcode": "host gmail-smtp-in.l.google.com[64.233.187.27] said: This mail has been blocked because the sender is unauthenticated. Gmail requires all senders to authenticate with either SPF or DKIM. Authentication results: DKIM = did not pass SPF [relay3.example.com] with ip: [192.0.2.22] = did not pass For instructions on setting up authentication, go to https://support.google.com/mail/answer/81126#authentication c2-202200202020202020222222cat.127 - gsmtp (in reply to end of DATA command)",
@@ -349,19 +350,19 @@ Differences between Sisimai 4 and Sisimai 5
349
350
 
350
351
  Features
351
352
  ---------------------------------------------------------------------------------------------------
352
- Sisimai 5.0.0から**Ruby 2.4以上**が必要になります。
353
+ Sisimai 5.5.0から**Ruby 2.5以上**が必要になります。
353
354
 
354
355
  | 機能 | Sisimai 4 | Sisimai 5 |
355
356
  |------------------------------------------------------|--------------------|---------------------|
356
- | 動作環境(CRuby) | 2.1 - 3.3.0 | **2.4** or later |
357
+ | 動作環境(CRuby) | 2.1 - 3.3.0 | **2.5** or later |
357
358
  | 動作環境(JRuby) | 9.0.4.0 - 9.1.17.0 | **9.2** or later |
358
359
  | 元メールファイルを操作可能なコールバック機能 | なし | あり[^3] |
359
- | 解析エンジン(MTA/ESPモジュール)の数 | 68 | 58 |
360
+ | 解析エンジン(MTA/ESPモジュール)の数 | 68 | 60 |
360
361
  | 検出可能なバウンス理由の数 | 29 | 36 |
361
362
  | 依存Gem数(Ruby Standard Gemsを除く) | 1 Gem | 1 Gem |
362
- | ソースコードの行数 | 10,800 行 | 9,860 行 |
363
+ | ソースコードの行数 | 10,800 行 | 9,970 行 |
363
364
  | テストフレームワーク | rspec | minitest |
364
- | テスト件数(spec/またはtest/ディレクトリ) | 311,000 件 | 410,000 件 |
365
+ | テスト件数(spec/またはtest/ディレクトリ) | 311,000 件 | 240,000 件 |
365
366
  | 1秒間に解析できるバウンスメール数[^4] | 620 通 | 620 通 |
366
367
  | ライセンス | 2条項BSD | 2条項BSD |
367
368
  | 開発会社による商用サポート | 提供中 | 提供中 |
@@ -401,7 +402,9 @@ Sisimai 5で3個のESPモジュール名(解析エンジン)が変更になり
401
402
  | Google Workspace | `Rhost::GoogleApps` | `Rhost::Google` |
402
403
  | Tencent | `Rhost::TencentQQ` | `Rhost::Tencent` |
403
404
  | Yahoo Mail (added at v5.1.0) | なし | `Rhost::YahooInc` |
405
+ | Zoho (added at v5.5.0) | なし | `Rhost::Zoho` |
404
406
  | DragonFly Mail Agent (added at v5.1.0) | なし | `Lhost::DragonFly` |
407
+ | Mimecast (added at v5.5.0) | なし | `Lhost::Mimecast` |
405
408
 
406
409
  Bounce Reasons
407
410
  ---------------------------------------------------------------------------------------------------
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ![](https://libsisimai.org/static/images/logo/sisimai-x01.png)
2
2
  [![License](https://img.shields.io/badge/license-BSD%202--Clause-orange.svg)](https://github.com/sisimai/rb-sisimai/blob/master/LICENSE)
3
- [![Ruby](https://img.shields.io/badge/ruby-v2.4.0--v3.4.0-red.svg)](https://www.ruby-lang.org/)
3
+ [![Ruby](https://img.shields.io/badge/ruby-v2.5.0--v3.4.0-red.svg)](https://www.ruby-lang.org/)
4
4
  [![Gem Version](https://badge.fury.io/rb/sisimai.svg)](https://badge.fury.io/rb/sisimai)
5
5
  [![codecov](https://codecov.io/github/sisimai/rb-sisimai/graph/badge.svg?token=YGkyluNWiZ)](https://codecov.io/github/sisimai/rb-sisimai)
6
6
 
@@ -17,7 +17,7 @@
17
17
  > If you are using one of these versions, please upgrade to v4.25.14p12 or later.**
18
18
 
19
19
  > [!WARNING]
20
- > Sisimai 5 requires Ruby 2.4 or later. Check the version of Ruby in your system before installing/upgrading
20
+ > Sisimai 5 requires Ruby 2.5 or later. Check the version of Ruby in your system before installing/upgrading
21
21
  > by `ruby -v` command.
22
22
 
23
23
  > [!NOTE]
@@ -67,14 +67,14 @@ of Sisimai is ported from [the Perl version of Sisimai](https://github.com/sisim
67
67
  The key features of Sisimai
68
68
  ---------------------------------------------------------------------------------------------------
69
69
  * __Decode email bounces to structured data__
70
- * Sisimai provides detailed insights into bounce emails by extracting 26 key data points.[^2]
70
+ * Sisimai provides detailed insights into bounce emails by extracting 27 key data points.[^2]
71
71
  * __Essential information__: `timestamp`, `origin`
72
72
  * __Sender information__: `addresser`, `senderdomain`,
73
73
  * __Recipient information__: `recipient`, `destination`, `alias`
74
74
  * __Delivery information__: `action`, `replycode`, `deliverystatus`, `command`
75
75
  * __Bounce details__: `reason`, `diagnosticcode`, `diagnostictype`, `feedbacktype`, `feedbackid`, `hardbounce`
76
76
  * __Message details__: `subject`, `messageid`, `listid`,
77
- * __Additional information__: `decodedby`, `timezoneoffset`, `lhost`, `rhost`, `token`, `catch`
77
+ * __Additional information__: `decodedby`, `timezoneoffset`, `lhost`, `rhost`, `token`, `catch`, `toxic`
78
78
  * Output formats
79
79
  * Ruby (Hash, Array)
80
80
  * JSON
@@ -85,7 +85,7 @@ The key features of Sisimai
85
85
  * `gem install`
86
86
  * `git clone && make`
87
87
  * __High Precision of Analysis__
88
- * Support [59 MTAs/MDAs/ESPs](https://libsisimai.org/en/engine/)
88
+ * Support [60 MTAs/MDAs/ESPs](https://libsisimai.org/en/engine/)
89
89
  * Support Feedback Loop Message(ARF)
90
90
  * Can detect [36 bounce reasons](https://libsisimai.org/en/reason/)
91
91
 
@@ -104,7 +104,7 @@ System requirements
104
104
  More details about system requirements are available at
105
105
  [Sisimai | Getting Started](https://libsisimai.org/en/start/) page.
106
106
 
107
- * [Ruby 2.4.0 or later](http://www.ruby-lang.org/)
107
+ * [Ruby 2.5.0 or later](http://www.ruby-lang.org/)
108
108
  * [__oj | The fastest JSON parser and object serializer__](https://rubygems.org/gems/oj)
109
109
  * Also works on [JRuby 9.2 or later](http://jruby.org)
110
110
  * [__jrjackson | A mostly native JRuby wrapper for the java jackson json processor jar__](https://rubygems.org/gems/jrjackson)
@@ -114,17 +114,17 @@ Install
114
114
  ### From RubyGems
115
115
  ```shell
116
116
  $ sudo gem install sisimai
117
- Fetching: sisimai-5.2.1.gem (100%)
118
- Successfully installed sisimai-5.2.1
119
- Parsing documentation for sisimai-5.2.1
120
- Installing ri documentation for sisimai-5.2.1
117
+ Fetching: sisimai-5.5.0.gem (100%)
118
+ Successfully installed sisimai-5.5.0
119
+ Parsing documentation for sisimai-5.5.0
120
+ Installing ri documentation for sisimai-5.5.0
121
121
  Done installing documentation for sisimai after 6 seconds
122
122
  1 gem installed
123
123
  ```
124
124
 
125
125
  ### From GitHub
126
126
  > [!WARNING]
127
- > Sisimai 5 requires Ruby 2.4 or later. Check the version of Ruby in your system before installing/upgrading
127
+ > Sisimai 5 requires Ruby 2.5 or later. Check the version of Ruby in your system before installing/upgrading
128
128
  > by `ruby -v` command.
129
129
 
130
130
  ```shell
@@ -145,13 +145,13 @@ if [ -d "/usr/local/jr" ]; then \
145
145
  ...
146
146
  3 gems installed
147
147
  /opt/local/bin/rake install
148
- sisimai 5.2.1 built to pkg/sisimai-5.2.1.gem.
149
- sisimai (5.2.1) installed.
148
+ sisimai 5.5.0 built to pkg/sisimai-5.5.0.gem.
149
+ sisimai (5.5.0) installed.
150
150
  if [ -d "/usr/local/jr" ]; then \
151
151
  PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
152
152
  fi
153
- sisimai 5.2.1 built to pkg/sisimai-5.2.1-java.gem.
154
- sisimai (5.2.1) installed.
153
+ sisimai 5.5.0 built to pkg/sisimai-5.5.0-java.gem.
154
+ sisimai (5.5.0) installed.
155
155
  ```
156
156
 
157
157
  Usage
@@ -332,6 +332,7 @@ Output example
332
332
  "timezoneoffset": "+0900",
333
333
  "replycode": 550,
334
334
  "token": "84656774898baa90660be3e12fe0526e108d4473",
335
+ "toxic": false,
335
336
  "diagnostictype": "SMTP",
336
337
  "timestamp": 1650119685,
337
338
  "diagnosticcode": "host gmail-smtp-in.l.google.com[64.233.187.27] said: This mail has been blocked because the sender is unauthenticated. Gmail requires all senders to authenticate with either SPF or DKIM. Authentication results: DKIM = did not pass SPF [relay3.example.com] with ip: [192.0.2.22] = did not pass For instructions on setting up authentication, go to https://support.google.com/mail/answer/81126#authentication c2-202200202020202020222222cat.127 - gsmtp (in reply to end of DATA command)",
@@ -348,19 +349,19 @@ differences are available at [Sisimai | Differences](https://libsisimai.org/en/d
348
349
 
349
350
  Features
350
351
  ---------------------------------------------------------------------------------------------------
351
- Beginning with v5.0.0, Sisimai requires **Ruby 2.4.0 or later.**
352
+ Beginning with v5.5.0, Sisimai requires **Ruby 2.5.0 or later.**
352
353
 
353
354
  | Features | Sisimai 4 | Sisimai 5 |
354
355
  |------------------------------------------------------|--------------------|---------------------|
355
- | System requirements (CRuby) | 2.1 - 3.3.0 | **2.4** or later |
356
+ | System requirements (CRuby) | 2.1 - 3.3.0 | **2.5** or later |
356
357
  | System requirements (JRuby) | 9.0.4.0 - 9.1.17.0 | **9.2** or later |
357
358
  | Callback feature for the original email file | N/A | Available[^3] |
358
- | The number of MTA/ESP modules | 68 | 59 |
359
+ | The number of MTA/ESP modules | 68 | 60 |
359
360
  | The number of detectable bounce reasons | 29 | 36 |
360
361
  | Dependencies (Except Ruby Standard Gems) | 1 gem | 1 gem |
361
- | Source lines of code | 10,300 lines | 9,800 lines |
362
+ | Source lines of code | 10,300 lines | 9,970 lines |
362
363
  | Test frameworks | rspec | minitest |
363
- | The number of tests in spec/ or test/ directory | 311,000 tests | 410,000 tests |
364
+ | The number of tests in spec/ or test/ directory | 311,000 tests | 240,000 tests |
364
365
  | The number of bounce emails decoded/sec (CRuby)[^4] | 620 emails | 620 emails |
365
366
  | License | 2 Clause BSD | 2 Caluse BSD |
366
367
  | Commercial support | Available | Available |
@@ -402,7 +403,9 @@ available at [LIBSISIMAI.ORG/EN/ENGINE](https://libsisimai.org/en/engine/)
402
403
  | Google Workspace | `Rhost::GoogleApps` | `Rhost::Google` |
403
404
  | Tencent | `Rhost::TencentQQ` | `Rhost::Tencent` |
404
405
  | Yahoo Mail (added at v5.1.0) | None | `Rhost::YahooInc` |
406
+ | Zoho (added at v5.5.0) | None | `Rhost::Zoho` |
405
407
  | DragonFly Mail Agent (added at v5.1.0) | None | `Lhost::DragonFly` |
408
+ | Mimecast (added at v5.5.0) | None | `Lhost::Mimecast` |
406
409
 
407
410
  Bounce Reasons
408
411
  ---------------------------------------------------------------------------------------------------
@@ -1,33 +1,6 @@
1
1
  module Sisimai
2
2
  # Sisimai::Address provide methods for dealing email address.
3
3
  class Address
4
- build_regular_expressions = lambda do
5
- # See http://www.ietf.org/rfc/rfc5322.txt
6
- # or http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html ...
7
- # addr-spec = local-part "@" domain
8
- # local-part = dot-atom / quoted-string / obs-local-part
9
- # domain = dot-atom / domain-literal / obs-domain
10
- # domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
11
- # dcontent = dtext / quoted-pair
12
- # dtext = NO-WS-CTL / ; Non white space controls
13
- # %d33-90 / ; The rest of the US-ASCII
14
- # %d94-126 ; characters not including "[", "]", or "\"
15
- re = {rfc5322: nil, ignored: nil, domain: nil}
16
- atom = %r([a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)o
17
- quoted_string = %r/"(?:\\[^\r\n]|[^\\"])*"/o
18
- domain_literal = %r/\[(?:\\[\x01-\x09\x0B-\x0c\x0e-\x7f]|[\x21-\x5a\x5e-\x7e])*\]/o
19
- dot_atom = %r/#{atom}(?:[.]#{atom})*/o
20
- local_part = %r/(?:#{dot_atom}|#{quoted_string})/o
21
- domain = %r/(?:#{dot_atom}|#{domain_literal})/o
22
-
23
- re[:rfc5322] = %r/\A#{local_part}[@]#{domain}\z/o
24
- re[:ignored] = %r/\A#{local_part}[.]*[@]#{domain}\z/o
25
- re[:domain] = %r/\A#{domain}\z/o
26
-
27
- return re
28
- end
29
-
30
- Re = build_regular_expressions.call
31
4
  Indicators = {
32
5
  :'email-address' => (1 << 0), # <neko@example.org>
33
6
  :'quoted-string' => (1 << 1), # "Neko, Nyaan"
@@ -47,9 +20,85 @@ module Sisimai
47
20
  # @param [String] email Email address string
48
21
  # @return [Boolean] true: is an email address, false: is not an email address
49
22
  def self.is_emailaddress(email)
50
- return false if email.is_a?(::String) == false
51
- return false if email =~ %r/(?:[\x00-\x1f]|\x1f)/ || email.size > 254
52
- return true if email =~ Re[:ignored]
23
+ return false if email.is_a?(::String) == false || email.size < 5;
24
+
25
+ email = email.strip
26
+ width = email.size
27
+ lasta = email.rindex('@') || -1
28
+
29
+ return false if width > 254; # The maximum length of an email address is 254
30
+ return false if lasta < 1 || lasta > 64 # The maximum length of a local part is 64
31
+ return false if width - lasta > 253 # The maximum length of a domain part is 252
32
+
33
+ quote = is_quotedaddress(email); if quote == false
34
+ # The email address is not a quoted address
35
+ ap = email.index('@') || -1
36
+ return false if ap != lasta # There are 2 or more '@'.
37
+ return false if email.index(' ') != nil # There is 1 or more ' '.
38
+ end
39
+
40
+ ipv46 = Sisimai::RFC1123.is_domainliteral(email)
41
+
42
+ j = -1; email.split('').each do |e|
43
+ # 31 < The ASCII code of each character < 127
44
+ p = e.ord; j += 1
45
+
46
+ if j < lasta
47
+ # The email address has quoted local part like "neko@cat"@example.org
48
+ return false if p < 32 || p > 126 # Before ' ' || After '~'
49
+ next if j == 0 # The character is the first character
50
+
51
+ if quote
52
+ # The email address has quoted local part like "neko@cat"@example.org
53
+ jp = email[j - 1, 1]
54
+ if jp.ord == 92 # 92 = '\'
55
+ # When the previous character IS '\', only the followings are allowed: '\', '"'
56
+ return false if p != 92 && p != 34
57
+ else
58
+ # When the previous character IS NOT '\'
59
+ return false if p == 34 && j + 1 < lasta
60
+ end
61
+ else
62
+ # The local part is not quoted
63
+ # ".." is not allowed in a local part when the local part is not quoted by "" but
64
+ # Non-RFC compliant email addresses still persist in the world.
65
+ #
66
+ # The following characters are not allowed in a local part without "..."@example.jp
67
+ return false if e == ',' || e == '@' || e == ':' || e == ';' || e == '('
68
+ return false if e == ')' || e == '<' || e == '>' || e == '[' || e == ']'
69
+ end
70
+ else
71
+ # A domain part of the email address: string after the last "@"
72
+ next if p == 64 # '@'
73
+ return false if p < 45 # Before '-'
74
+ return false if p == 47 # Equals '/'
75
+ return false if p == 92 # Equals '\'
76
+ return false if p > 122 # After 'z'
77
+
78
+ if ipv46 == false
79
+ # Such as "example.jp", "neko.example.org"
80
+ return false if p > 57 && p < 64 # ':' to '?'
81
+ return false if p > 90 && p < 97 # '[' to '`'
82
+ else
83
+ # Such as "[IPv4:192.0.2.25]"
84
+ return false if p > 59 && p < 64 # ';' to '?'
85
+ return false if p > 93 && p < 97 # '^' to '`'
86
+ end
87
+ end
88
+ end
89
+ return true if ipv46
90
+
91
+ # Check that the domain part is a valid internet host or not
92
+ return Sisimai::RFC1123.is_internethost(email[lasta + 1, 255])
93
+ end
94
+
95
+ # Checks that the local part of the argument is quoted address or not.
96
+ # @param [String] argv0 Email address
97
+ # @return [True,False] false: is not a quoted address
98
+ # true: is a quoted address
99
+ def self.is_quotedaddress(argv0)
100
+ return false if argv0.is_a?(::String) == false
101
+ return true if argv0.start_with?('"') && argv0.include?('"@')
53
102
  return false
54
103
  end
55
104
 
@@ -80,7 +129,7 @@ module Sisimai
80
129
  # @example Parse email address
81
130
  # find('Neko <neko(nyaan)@example.org>')
82
131
  # #=> [{ address: 'neko@example.org', name: 'Neko', comment: '(nyaan)'}]
83
- return nil unless argv1
132
+ return nil if argv1.nil? || argv1.empty?
84
133
 
85
134
  emailtable = {address: '', name: '', comment: ''}
86
135
  addrtables = []
@@ -217,7 +266,7 @@ module Sisimai
217
266
  else
218
267
  # Display name like "Neko, Nyaan"
219
268
  v[:name] += e
220
- next unless readcursor & Indicators[:'quoted-string'] > 0
269
+ next if readcursor & Indicators[:'quoted-string'] == 0
221
270
  next if v[:name].end_with?(%Q|\x5c"|) # "Neko, Nyaan \"...
222
271
  readcursor &= ~Indicators[:'quoted-string']
223
272
  p = ''
@@ -245,7 +294,7 @@ module Sisimai
245
294
  v[:address] = v[:name]
246
295
  end
247
296
 
248
- unless v[:address].empty?
297
+ if v[:address].empty? == false
249
298
  # Remove the comment from the address
250
299
  if Sisimai::String.aligned(v[:address], ['(', ')'])
251
300
  # (nyaan)nekochan@example.org, nekochan(nyaan)cat@example.org or nekochan(nyaan)@example.org
@@ -263,14 +312,14 @@ module Sisimai
263
312
  next if e[:address] =~ /[^\x20-\x7e]/
264
313
  if e[:address].include?('@') == false
265
314
  # Allow if the argument is MAILER-DAEMON
266
- next unless Sisimai::Address.is_mailerdaemon(e[:address])
315
+ next if Sisimai::Address.is_mailerdaemon(e[:address]) == false
267
316
  end
268
317
 
269
318
  # Remove angle brackets, other brackets, and quotations: []<>{}'` except a domain part is
270
319
  # an IP address like neko@[192.0.2.222]
271
320
  e[:address] = e[:address].gsub(/\A[\[<{('`]/, '').gsub(/[.,'`>});]\z/, '')
272
- e[:address] = e[:address].gsub(/[^A-Za-z]\z/, '') unless e[:address].include?('@[')
273
- e[:address] = e[:address].sub(/\A["]/, '').chomp('"') unless e[:address] =~ /\A["].+["][@]/
321
+ e[:address] = e[:address].gsub(/[^A-Za-z]\z/, '') if e[:address].include?('@[') == false
322
+ e[:address] = e[:address].delete_prefix('"').delete_suffix('"') if is_quotedaddress(e[:address]) == false
274
323
 
275
324
  if addrs
276
325
  # Almost compatible with parse() method, returns email address only
@@ -279,10 +328,10 @@ module Sisimai
279
328
  else
280
329
  # Remove double-quotations, trailing spaces.
281
330
  [:name, :comment].each { |f| e[f] = e[f].strip }
282
- e[:comment] = '' unless e[:comment] =~ /\A[(].+[)]/
283
- e[:name].squeeze!(' ') unless e[:name] =~ /\A["].+["]\z/
284
- e[:name].sub!(/\A["]/, '') unless e[:name] =~ /\A["].+["][@]/
285
- e[:name].chomp!('"')
331
+ e[:comment] = '' unless e[:comment] =~ /\A[(].+[)]/
332
+ e[:name].squeeze!(' ') unless e[:name] =~ /\A["].+["]\z/
333
+ e[:name].delete_prefix!('"') unless is_quotedaddress(e[:name])
334
+ e[:name].delete_suffix!('"')
286
335
  end
287
336
  addrtables << e
288
337
  end
@@ -322,7 +371,7 @@ module Sisimai
322
371
  # @example Expand alias
323
372
  # expand_alias('neko+straycat@example.org') #=> 'neko@example.org'
324
373
  def self.expand_alias(email)
325
- return "" unless Sisimai::Address.is_emailaddress(email)
374
+ return "" if Sisimai::Address.is_emailaddress(email) == false
326
375
 
327
376
  local = email.split('@')
328
377
  return "" unless cv = local[0].match(/\A([-\w]+?)[+].+\z/)
@@ -353,7 +402,7 @@ module Sisimai
353
402
  argvs[:address].match(/\A(["].+?["])[@]([^@]+)\z/)
354
403
  # Get the local part and the domain part from the email address
355
404
  lpart = argvs[:address][0, point]
356
- dpart = argvs[:address][point + 1, argvs[:address].size]
405
+ dpart = argvs[:address][point + 1, argvs[:address].size]
357
406
  email = Sisimai::Address.expand_verp(argvs[:address])
358
407
  aname = nil
359
408
 
@@ -391,8 +440,7 @@ module Sisimai
391
440
  @address = lpart + '@' + dpart
392
441
  else
393
442
  # The argument does not include "@"
394
- return nil unless Sisimai::Address.is_mailerdaemon(argvs[:address])
395
- return nil if argvs[:address].include?(' ')
443
+ return nil if Sisimai::Address.is_mailerdaemon(argvs[:address]) == false || argvs[:address].include?(' ')
396
444
 
397
445
  # The argument does not include " "
398
446
  @user = argvs[:address]
data/lib/sisimai/arf.rb CHANGED
@@ -36,7 +36,7 @@ module Sisimai
36
36
  # @return [True,False] true: Feedback Loop
37
37
  # false: is not Feedback loop
38
38
  def is_arf(heads)
39
- return false unless heads
39
+ return false if heads.nil?
40
40
 
41
41
  # Content-Type: multipart/report; report-type=feedback-report; ...
42
42
  return true if Sisimai::String.aligned(heads["content-type"], ["report-type=", "feedback-report"])
@@ -54,7 +54,7 @@ module Sisimai
54
54
  end
55
55
 
56
56
  # X-Apple-Unsubscribe: true
57
- return false unless heads.has_key?("x-apple-unsubscribe")
57
+ return false if heads.has_key?("x-apple-unsubscribe") == false
58
58
  return true if heads["x-apple-unsubscribe"] == "true"
59
59
  return false
60
60
  end
@@ -65,7 +65,7 @@ module Sisimai
65
65
  # @return [Hash] Bounce data list and message/rfc822 part
66
66
  # @return [Nil] it failed to decode or the arguments are missing
67
67
  def inquire(mhead, mbody)
68
- return nil unless self.is_arf(mhead)
68
+ return nil if self.is_arf(mhead) == false
69
69
 
70
70
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = dscontents[-1]
71
71
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
@@ -109,7 +109,7 @@ module Sisimai
109
109
  ARFPreface.each do |f|
110
110
  # Hello,
111
111
  # this is an autogenerated email abuse complaint regarding your network.
112
- next unless Sisimai::String.aligned(r, f)
112
+ next if Sisimai::String.aligned(r, f) == false
113
113
  readcursor |= Indicators[:deliverystatus]
114
114
  v["diagnosis"] += " #{e}"
115
115
  break
@@ -131,7 +131,7 @@ module Sisimai
131
131
  # Original-Rcpt-To header field is optional and may appear any number of times as appropriate:
132
132
  # Original-Rcpt-To: <kijitora@example.jp>
133
133
  # Removal-Recipient: user@example.com
134
- cv = Sisimai::Address.s3s4(e[e.index(" ") + 1, e.size]); next unless Sisimai::Address.is_emailaddress(cv)
134
+ cv = Sisimai::Address.s3s4(e[e.index(" ") + 1, e.size]); next if Sisimai::Address.is_emailaddress(cv) == false
135
135
  cw = dscontents.size; next if cw > 0 && cv == dscontents[cw - 1]["recipient"]
136
136
 
137
137
  if v["recipient"] != ""
@@ -191,8 +191,7 @@ module Sisimai
191
191
  # There is no recipient address in the message
192
192
  if mhead.has_key?("x-apple-unsubscribe")
193
193
  # X-Apple-Unsubscribe: true
194
- last unless mhead["x-apple-unsubscribe"] == "true"
195
- last unless mhead["from"].include?('@')
194
+ last if mhead["x-apple-unsubscribe"] != "true" || mhead["from"].include?('@') == false
196
195
  dscontents[0]["recipient"] = mhead["from"]
197
196
  dscontents[0]["diagnosis"] = Sisimai::String.sweep(emailparts[0])
198
197
  dscontents[0]["feedbacktype"] = "opt-out"
@@ -208,7 +207,7 @@ module Sisimai
208
207
 
209
208
  # There is no valid email address in the To: header of the original message such as
210
209
  # To: <Undisclosed Recipients>
211
- cv = Sisimai::Address.undisclosed("r") unless Sisimai::Address.is_emailaddress(cv)
210
+ cv = Sisimai::Address.undisclosed("r") if Sisimai::Address.is_emailaddress(cv) == false
212
211
  dscontents[0]["recipient"] = cv
213
212
  end
214
213
  recipients += 1
@@ -203,7 +203,7 @@ module Sisimai
203
203
  # The piece is the value of a day
204
204
  if v[:d]
205
205
  # 2-digit year?
206
- altervalue[:Y] = p unless v[:Y]
206
+ altervalue[:Y] = p if v[:Y].nil?
207
207
  else
208
208
  # The value is "day"
209
209
  v[:d] = p
@@ -361,7 +361,7 @@ module Sisimai
361
361
  # @example Get timezone offset string of specified seconds
362
362
  # second2tz(12345) #=> '+0325'
363
363
  def second2tz(argv1)
364
- return '+0000' unless argv1.is_a?(::Integer)
364
+ return '+0000' if argv1.is_a?(::Integer) == false
365
365
  return "" if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
366
366
 
367
367
  digit = {:operator => '+'}