sisimai 5.0.1 → 5.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codecovio.yml +33 -0
  3. data/.github/workflows/rake-test.yml +54 -0
  4. data/ChangeLog.md +55 -0
  5. data/Gemfile +2 -0
  6. data/README-JA.md +14 -14
  7. data/README.md +15 -16
  8. data/lib/sisimai/arf.rb +24 -5
  9. data/lib/sisimai/fact.rb +46 -8
  10. data/lib/sisimai/lhost/amazonses.rb +0 -1
  11. data/lib/sisimai/lhost/amazonworkmail.rb +0 -1
  12. data/lib/sisimai/lhost/aol.rb +0 -1
  13. data/lib/sisimai/lhost/bigfoot.rb +0 -1
  14. data/lib/sisimai/lhost/domino.rb +0 -1
  15. data/lib/sisimai/lhost/exchange2007.rb +1 -1
  16. data/lib/sisimai/lhost/exim.rb +7 -16
  17. data/lib/sisimai/lhost/facebook.rb +0 -1
  18. data/lib/sisimai/lhost/googlegroups.rb +2 -1
  19. data/lib/sisimai/lhost/gsuite.rb +0 -1
  20. data/lib/sisimai/lhost/mailmarshalsmtp.rb +1 -1
  21. data/lib/sisimai/lhost/mailru.rb +8 -17
  22. data/lib/sisimai/lhost/messagelabs.rb +0 -1
  23. data/lib/sisimai/lhost/mfilter.rb +1 -1
  24. data/lib/sisimai/lhost/mxlogic.rb +8 -18
  25. data/lib/sisimai/lhost/office365.rb +1 -1
  26. data/lib/sisimai/lhost/outlook.rb +0 -1
  27. data/lib/sisimai/lhost/postfix.rb +0 -1
  28. data/lib/sisimai/lhost/receivingses.rb +0 -1
  29. data/lib/sisimai/lhost/sendgrid.rb +1 -3
  30. data/lib/sisimai/lhost/sendmail.rb +0 -1
  31. data/lib/sisimai/lhost/yandex.rb +0 -1
  32. data/lib/sisimai/message.rb +14 -5
  33. data/lib/sisimai/reason/authfailure.rb +1 -0
  34. data/lib/sisimai/reason/blocked.rb +3 -0
  35. data/lib/sisimai/reason/expired.rb +8 -0
  36. data/lib/sisimai/reason/filtered.rb +1 -0
  37. data/lib/sisimai/reason/mailboxfull.rb +4 -0
  38. data/lib/sisimai/reason/norelaying.rb +1 -0
  39. data/lib/sisimai/reason/rejected.rb +1 -1
  40. data/lib/sisimai/reason/securityerror.rb +1 -0
  41. data/lib/sisimai/reason/spamdetected.rb +1 -0
  42. data/lib/sisimai/reason/suspend.rb +5 -0
  43. data/lib/sisimai/reason/userunknown.rb +4 -1
  44. data/lib/sisimai/rfc5322.rb +120 -64
  45. data/lib/sisimai/rhost/google.rb +82 -67
  46. data/lib/sisimai/rhost/microsoft.rb +8 -0
  47. data/lib/sisimai/rhost/mimecast.rb +9 -2
  48. data/lib/sisimai/rhost/nttdocomo.rb +3 -3
  49. data/lib/sisimai/version.rb +1 -1
  50. data/set-of-emails/maildir/bsd/arf-26.eml +27 -0
  51. data/set-of-emails/maildir/bsd/lhost-sendmail-60.eml +85 -0
  52. data/set-of-emails/maildir/bsd/rhost-microsoft-04.eml +86 -0
  53. data/set-of-emails/maildir/bsd/rhost-microsoft-05.eml +83 -0
  54. metadata +8 -3
  55. data/.travis.yml +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f3ea96ca0a6350d1b5b085191d287c061459de6be048ecc6cc1a115509adcef
4
- data.tar.gz: 2305366582fd23ba18f9db19d21b33c6d714f871435aa6b2601b3c421a749fe9
3
+ metadata.gz: 0eec943ed278f831725b0284faaee55afd03e0a9c1c843ff6ea5b293e557fe9b
4
+ data.tar.gz: 2491ec5afc09217998fad153605ccabf5fbe6ae66fceecc70b5798f17c0120f7
5
5
  SHA512:
6
- metadata.gz: 795bf696fc7accdcb2835f9cdd719e3c61dc3b84a8dec864e65fc325a1499dde22593edba19584ba47bb6b485c90ce9fbfb49a962b3cd920695c6564eef28a9c
7
- data.tar.gz: 4b28f1877c47f788ba5ad72bce4a22931b651534c5c7096c3dd30c5c75f11fcc4401c605915e2becdf168015a471a04a73cf7b3fca0f85e1cfeb11073057a4b4
6
+ metadata.gz: 35d9e9b9360bd120b9ba66d3a316536796834eb260f29ab0d0054466ea71c998eb315051fc820cbecd5676d212d410ae28c2402ed7457609d3211b425798898d
7
+ data.tar.gz: '09e8845d7dd05b8d1b3931438e755411427c720e0e25f31c70c37d4bb460659fdf74110096cfda7a6a968d1f1af7423fc262f88f159952ff7637cc72bdc8f3dc'
@@ -0,0 +1,33 @@
1
+ name: Upload coverage reports to Codecov
2
+ on:
3
+ push:
4
+ branches: ["5-stable"]
5
+ pull_request:
6
+ branches: ["5-stable"]
7
+ jobs:
8
+ codecov:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout the repository(CRuby)
12
+ uses: actions/checkout@v4
13
+ - name: Setup CRuby
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: "3.3"
17
+ - name: Install minitest
18
+ run: gem install minitest -v 5.15.0
19
+ - name: Install oj
20
+ run: gem install oj -v 3.10.0
21
+ - name: Install bundle, rake, simplecov, and simplecov-cobertura
22
+ run: gem install bundle rake simplecov simplecov-cobertura
23
+ - name: Check the CRuby version
24
+ run: ruby -v
25
+ - name: Execute public tests with the coverage report
26
+ run: ruby -I./lib ./test/coverage.rb
27
+ - name: Run Codecov on GitHub Actions
28
+ uses: codecov/codecov-action@v4.4.0
29
+ with:
30
+ token: ${{ secrets.CODECOV_TOKEN }}
31
+ files: ./coverage/coverage.xml
32
+ verbose: true
33
+
@@ -0,0 +1,54 @@
1
+ name: rake test
2
+ on:
3
+ push:
4
+ branches: ["5-stable"]
5
+ pull_request:
6
+ branches: ["5-stable"]
7
+ jobs:
8
+ test-cruby:
9
+ name: rake test with CRuby ${{ matrix.cruby }}
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ cruby: ["2.4", "3.3"]
15
+ steps:
16
+ - name: Checkout the repository(CRuby)
17
+ uses: actions/checkout@v4
18
+ - name: Setup CRuby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.cruby }}
22
+ - name: Install minitest
23
+ run: gem install minitest -v 5.15.0
24
+ - name: Install oj
25
+ run: gem install oj -v 3.10.0
26
+ - name: Install bundle and rake
27
+ run: gem install bundle rake
28
+ - name: Check the CRuby version
29
+ run: ruby -v
30
+ - name: Execute public tests
31
+ run: rake publictest
32
+ test-jruby:
33
+ name: rake test with JRuby ${{ matrix.jruby }}
34
+ runs-on: ubuntu-latest
35
+ strategy:
36
+ fail-fast: false
37
+ matrix:
38
+ jruby: ["jruby-9.2", "jruby-9.4"]
39
+ steps:
40
+ - name: Checkout the repository(JRuby)
41
+ uses: actions/checkout@v2
42
+ - name: Setup JRuby
43
+ uses: ruby/setup-ruby@v1
44
+ with:
45
+ ruby-version: ${{ matrix.jruby }}
46
+ - name: Install minitest
47
+ run: gem install minitest -v 5.15.0
48
+ - name: Install bundle, rake, and jrjackson
49
+ run: gem install bundle rake jrjackson
50
+ - name: Check the JRuby version
51
+ run: jruby -v
52
+ - name: Execute public tests
53
+ run: rake publictest
54
+
data/ChangeLog.md CHANGED
@@ -3,6 +3,61 @@ 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.0.3
7
+ ---------------------------------------------------------------------------------------------------
8
+ - release: "Wed, 22 May 2024 14:12:22 +0900 (JST)"
9
+ - version: "5.0.3"
10
+ - changes:
11
+ - Remove `.travis.yml` from this repository
12
+ - Follow updates in Gmail SMTP errors and codes on Apr 29 and May 10 at `Sisimai::Rhost::Google`
13
+ #275 #277 #283
14
+ - https://support.google.com/a/answer/3726730?hl=en
15
+ - https://github.com/azumakuniyuki/feb-2024-no-auth-no-entry/commit/1d6adede
16
+ - https://github.com/azumakuniyuki/feb-2024-no-auth-no-entry/commit/d477b178
17
+ - Implement SMTP error codes as follows: `4.7.23`, `4.7.30`, `4.7.32`, `5.7.29`, and `5.7.30`
18
+ - Shortened error message patterns to make them more adaptable to minor sentence changes.
19
+ - Multibyte characters in the code and comments have been replaced with ASCII characters #278
20
+ - #279 #280 Deal the Apple unsubscribe notification as an ARF message. Thanks to @mnmallea
21
+ - Add the following error message patterns returned from Exchange Online #281
22
+ - 4.4.317, 5.4.317: STARTTLS is required to send mail
23
+ - 4.4.318, 5.4.318: Connection was closed abruptly (SuspiciousRemoteServerError)
24
+ - #282 Added 16 error message patterns into the following reasons:
25
+ - `Blocked`
26
+ - `Expired`
27
+ - `Filtered`
28
+ - `MailboxFull`
29
+ - `NoRelaying`
30
+ - `Suspend`
31
+ - `UserUnknown`
32
+ - #286 Use Codecov for the coverage
33
+
34
+ v5.0.2
35
+ ---------------------------------------------------------------------------------------------------
36
+ - release: "Wed, 13 Mar 2024 13:00:00 +0900 (JST)"
37
+ - version: "5.0.2"
38
+ - changes:
39
+ - #271 #267 Sisimai 5 works on JRuby again. Thanks to @hiroyuki-sato
40
+ - #159 Implement workarounds at `Sisimai::Fact` and some public tests with `DateTime` class to
41
+ run Sisimai on JRuby, to avoid failing `strptime()`
42
+ - #269 Replace `Array#append` with `Array#push` at `Sisimai::RFC5322` because `Array#append` is
43
+ only available in Ruby 2.5 and above
44
+ - We have started testing JRuby 9.2 and 9.4 on GitHub Actions
45
+ - Disable 2 tests in `test/public/mail-test.rb` that fails on GitHub Actions only
46
+ - `5.7.23` returned from Office365 is an error related to SPF vilation (authfailure)
47
+ - #272 Fixed an issue that Sisimai could not get the value of `alias` address correctly when an
48
+ email forwarded and bounced
49
+ - `Sisimai::RFC5322.received` now returns a list including all the elements except date time and
50
+ (comments) found in the `Received` header
51
+ - Update the error message patterns in `Sisimai::Rhost::Mimecast`
52
+ - Update the error message patterns in the followings:
53
+ - `AuthFailure`
54
+ - `Blocked`
55
+ - `Expired`
56
+ - `MailboxFull`
57
+ - `SecurityError`
58
+ - `SpamDetected`
59
+ - `Suspend`
60
+
6
61
  v5.0.1
7
62
  ---------------------------------------------------------------------------------------------------
8
63
  - release: "Sun, 3 Mar 2024 17:17:17 +0900 (JST)"
data/Gemfile CHANGED
@@ -7,5 +7,7 @@ group :development, :test do
7
7
  gem 'rake', :require => false
8
8
  gem 'minitest', :require => false
9
9
  gem 'coveralls', :require => false
10
+ gem 'simplecov', :require => false
11
+ gem 'simplecov-cobertura', :require => false
10
12
  end
11
13
 
data/README-JA.md CHANGED
@@ -1,8 +1,8 @@
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
- [![Coverage Status](https://img.shields.io/coveralls/sisimai/rb-sisimai.svg)](https://coveralls.io/r/sisimai/rb-sisimai)
4
3
  [![Ruby](https://img.shields.io/badge/ruby-v2.4.0--v3.3.0-red.svg)](https://www.ruby-lang.org/)
5
4
  [![Gem Version](https://badge.fury.io/rb/sisimai.svg)](https://badge.fury.io/rb/sisimai)
5
+ [![codecov](https://codecov.io/github/sisimai/rb-sisimai/graph/badge.svg?token=YGkyluNWiZ)](https://codecov.io/github/sisimai/rb-sisimai)
6
6
 
7
7
  > [!IMPORTANT]
8
8
  > **2024年2月2日の時点でこのリポジトリのデフォルトブランチは[5-stable](https://github.com/sisimai/rb-sisimai/tree/5-stable)
@@ -102,7 +102,7 @@ Sisimaiの動作環境についての詳細は[Sisimai | シシマイを使っ
102
102
 
103
103
  * [Ruby 2.4.0 or later](http://www.ruby-lang.org/)
104
104
  * [__oj | The fastest JSON parser and object serializer__](https://rubygems.org/gems/oj)
105
- * Also works on [JRuby 9.0.4.0 - 9.1.17.0](http://jruby.org)
105
+ * Also works on [JRuby 9.2 or later](http://jruby.org)
106
106
  * [__jrjackson | A mostly native JRuby wrapper for the java jackson json processor jar__](https://rubygems.org/gems/jrjackson)
107
107
 
108
108
  Install
@@ -110,10 +110,10 @@ Install
110
110
  ### From RubyGems.org
111
111
  ```shell
112
112
  $ sudo gem install sisimai
113
- Fetching: sisimai-5.0.1.gem (100%)
114
- Successfully installed sisimai-5.0.1
115
- Parsing documentation for sisimai-5.0.1
116
- Installing ri documentation for sisimai-5.0.1
113
+ Fetching: sisimai-5.0.3.gem (100%)
114
+ Successfully installed sisimai-5.0.3
115
+ Parsing documentation for sisimai-5.0.3
116
+ Installing ri documentation for sisimai-5.0.3
117
117
  Done installing documentation for sisimai after 6 seconds
118
118
  1 gem installed
119
119
  ```
@@ -141,13 +141,13 @@ if [ -d "/usr/local/jr" ]; then \
141
141
  ...
142
142
  3 gems installed
143
143
  /opt/local/bin/rake install
144
- sisimai 5.0.0 built to pkg/sisimai-5.0.0.gem.
145
- sisimai (5.0.0) installed.
144
+ sisimai 5.0.3 built to pkg/sisimai-5.0.3.gem.
145
+ sisimai (5.0.3) installed.
146
146
  if [ -d "/usr/local/jr" ]; then \
147
147
  PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
148
148
  fi
149
- sisimai 5.0.0 built to pkg/sisimai-5.0.0-java.gem.
150
- sisimai (5.0.0) installed.
149
+ sisimai 5.0.3 built to pkg/sisimai-5.0.3-java.gem.
150
+ sisimai (5.0.3) installed.
151
151
  ```
152
152
 
153
153
  Usage
@@ -348,15 +348,15 @@ Sisimai 5.0.0から**Ruby 2.4以上**が必要になります。
348
348
 
349
349
  | 機能 | Sisimai 4 | Sisimai 5 |
350
350
  |------------------------------------------------------|--------------------|---------------------|
351
- | 動作環境(CRuby) | 2.1 - | **2.4** - 3.3.0 |
352
- | 動作環境(JRuby) | 9.0.4.0 - 9.1.17.0 | 9.0.4.0 - 9.1.17.0 |
351
+ | 動作環境(CRuby) | 2.1 - | **2.4** or later |
352
+ | 動作環境(JRuby) | 9.0.4.0 - 9.1.17.0 | **9.2** or later |
353
353
  | 元メールファイルを操作可能なコールバック機能 | なし | あり[^3] |
354
354
  | 解析エンジン(MTA/ESPモジュール)の数 | 68 | 70 |
355
355
  | 検出可能なバウンス理由の数 | 29 | 34 |
356
356
  | 依存Gem数(Ruby Standard Gemsを除く) | 1 Gem | 1 Gem |
357
- | ソースコードの行数 | 10,800 行 | 11,400 行 |
357
+ | ソースコードの行数 | 10,800 行 | 11,370 行 |
358
358
  | テストフレームワーク | rspec | minitest |
359
- | テスト件数(spec/またはtest/ディレクトリ) | 311,000 件 | 336,000 件 |
359
+ | テスト件数(spec/またはtest/ディレクトリ) | 311,000 件 | 338,000 件 |
360
360
  | 1秒間に解析できるバウンスメール数[^4] | 231 通 | 305 通 |
361
361
  | ライセンス | 2条項BSD | 2条項BSD |
362
362
  | 開発会社による商用サポート | 提供中 | 提供中 |
data/README.md CHANGED
@@ -1,8 +1,8 @@
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
- [![Coverage Status](https://img.shields.io/coveralls/sisimai/rb-sisimai.svg)](https://coveralls.io/r/sisimai/rb-sisimai)
4
3
  [![Ruby](https://img.shields.io/badge/ruby-v2.4.0--v3.3.0-red.svg)](https://www.ruby-lang.org/)
5
4
  [![Gem Version](https://badge.fury.io/rb/sisimai.svg)](https://badge.fury.io/rb/sisimai)
5
+ [![codecov](https://codecov.io/github/sisimai/rb-sisimai/graph/badge.svg?token=YGkyluNWiZ)](https://codecov.io/github/sisimai/rb-sisimai)
6
6
 
7
7
  > [!IMPORTANT]
8
8
  > **The default branch of this repository is [5-stable](https://github.com/sisimai/rb-sisimai/tree/5-stable)
@@ -99,10 +99,9 @@ System requirements
99
99
  More details about system requirements are available at
100
100
  [Sisimai | Getting Started](https://libsisimai.org/en/start/) page.
101
101
 
102
-
103
102
  * [Ruby 2.4.0 or later](http://www.ruby-lang.org/)
104
103
  * [__oj | The fastest JSON parser and object serializer__](https://rubygems.org/gems/oj)
105
- * Also works on [JRuby 9.0.4.0 - 9.1.17.0](http://jruby.org)
104
+ * Also works on [JRuby 9.2 or later](http://jruby.org)
106
105
  * [__jrjackson | A mostly native JRuby wrapper for the java jackson json processor jar__](https://rubygems.org/gems/jrjackson)
107
106
 
108
107
  Install
@@ -110,10 +109,10 @@ Install
110
109
  ### From RubyGems
111
110
  ```shell
112
111
  $ sudo gem install sisimai
113
- Fetching: sisimai-5.0.1.gem (100%)
114
- Successfully installed sisimai-5.0.1
115
- Parsing documentation for sisimai-5.0.1
116
- Installing ri documentation for sisimai-5.0.1
112
+ Fetching: sisimai-5.0.3.gem (100%)
113
+ Successfully installed sisimai-5.0.3
114
+ Parsing documentation for sisimai-5.0.3
115
+ Installing ri documentation for sisimai-5.0.3
117
116
  Done installing documentation for sisimai after 6 seconds
118
117
  1 gem installed
119
118
  ```
@@ -141,13 +140,13 @@ if [ -d "/usr/local/jr" ]; then \
141
140
  ...
142
141
  3 gems installed
143
142
  /opt/local/bin/rake install
144
- sisimai 5.0.0 built to pkg/sisimai-5.0.0.gem.
145
- sisimai (5.0.0) installed.
143
+ sisimai 5.0.3 built to pkg/sisimai-5.0.3.gem.
144
+ sisimai (5.0.3) installed.
146
145
  if [ -d "/usr/local/jr" ]; then \
147
146
  PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
148
147
  fi
149
- sisimai 5.0.0 built to pkg/sisimai-5.0.0-java.gem.
150
- sisimai (5.0.0) installed.
148
+ sisimai 5.0.3 built to pkg/sisimai-5.0.3-java.gem.
149
+ sisimai (5.0.3) installed.
151
150
  ```
152
151
 
153
152
  Usage
@@ -302,7 +301,7 @@ One-Liner
302
301
 
303
302
  Output example
304
303
  ---------------------------------------------------------------------------------------------------
305
- ![](https://libsisimai.org/static/images/demo/sisimai-5-cli-dump-p01.gif)
304
+ ![](https://libsisimai.org/static/images/demo/sisimai-5-cli-dump-r01.gif)
306
305
 
307
306
  ```json
308
307
  [
@@ -348,15 +347,15 @@ Beginning with v5.0.0, Sisimai requires **Ruby 2.4.0 or later.**
348
347
 
349
348
  | Features | Sisimai 4 | Sisimai 5 |
350
349
  |------------------------------------------------------|--------------------|---------------------|
351
- | System requirements (CRuby) | 2.1 - 3.3.0 | **2.4** - 3.3.0 |
352
- | System requirements (JRuby) | 9.0.4.0 - 9.1.17.0 | 9.0.4.0 - 9.1.17.0 |
350
+ | System requirements (CRuby) | 2.1 - 3.3.0 | **2.4** or later |
351
+ | System requirements (JRuby) | 9.0.4.0 - 9.1.17.0 | **9.2** or later |
353
352
  | Callback feature for the original email file | N/A | Available[^3] |
354
353
  | The number of MTA/ESP modules | 68 | 70 |
355
354
  | The number of detectable bounce reasons | 29 | 34 |
356
355
  | Dependencies (Except Ruby Standard Gems) | 1 gem | 1 gem |
357
- | Source lines of code | 10,300 lines | 11,300 lines |
356
+ | Source lines of code | 10,300 lines | 11,370 lines |
358
357
  | Test frameworks | rspec | minitest |
359
- | The number of tests in spec/ or test/ directory | 311,000 tests | 336,000 tests |
358
+ | The number of tests in spec/ or test/ directory | 311,000 tests | 338,000 tests |
360
359
  | The number of bounce emails decoded/sec (CRuby)[^4] | 231 emails | 305 emails |
361
360
  | License | 2 Clause BSD | 2 Caluse BSD |
362
361
  | Commercial support | Available | Available |
data/lib/sisimai/arf.rb CHANGED
@@ -37,13 +37,12 @@ module Sisimai
37
37
  # false: is not Feedback loop
38
38
  def is_arf(heads)
39
39
  return false unless heads
40
- match = false
41
40
 
42
- if Sisimai::String.aligned(heads['content-type'], ['report-type=', 'feedback-report'])
43
- # Content-Type: multipart/report; report-type=feedback-report; ...
44
- match = true
41
+ # Content-Type: multipart/report; report-type=feedback-report; ...
42
+ return true if Sisimai::String.aligned(heads['content-type'], ['report-type=', 'feedback-report'])
45
43
 
46
- elsif heads['content-type'].include?('multipart/mixed')
44
+ match = false
45
+ if heads['content-type'].include?('multipart/mixed')
47
46
  # Microsoft (Hotmail, MSN, Live, Outlook) uses its own report format.
48
47
  # Amazon SES Complaints bounces
49
48
  cv = Sisimai::Address.s3s4(heads['from'])
@@ -54,6 +53,8 @@ module Sisimai
54
53
  match = true if ReportFrom.any? { |a| cv.include?(a) }
55
54
  end
56
55
  end
56
+ match = true if heads['x-apple-unsubscribe'] == 'true'
57
+
57
58
  return match
58
59
  end
59
60
 
@@ -280,6 +281,24 @@ module Sisimai
280
281
  arfheaders['rhost'] = mhead['subject'][mhead['subject'].rindex(' ') + 1, mhead['subject'].size]
281
282
  commondata['diagnosis'] =
282
283
  'This is a Microsoft email abuse report for an email message received from IP' << arfheaders['rhost'] + ' on ' << mhead['date']
284
+
285
+ elsif mhead['subject'].include?('unsubscribe')
286
+ # Apple Mail sent this email to unsubscribe from the message
287
+ while true
288
+ # Subject: unsubscribe
289
+ # Content-Type: text/plain; charset=UTF-8
290
+ # Auto-Submitted: auto-replied
291
+ # X-Apple-Unsubscribe: true
292
+ #
293
+ # Apple Mail sent this email to unsubscribe from the message
294
+ break unless mhead['x-apple-unsubscribe']
295
+ break unless mhead['x-apple-unsubscribe'] == 'true'
296
+ break unless mbody.include?('Apple Mail sent this email to unsubscribe from the message');
297
+
298
+ dscontents[-1]['recipient'] = Sisimai::Address.s3s4(mhead['from'])
299
+ dscontents[-1]['feedbacktype'] = 'opt-out'
300
+ break
301
+ end
283
302
  end
284
303
 
285
304
  dscontents.each do |e|
data/lib/sisimai/fact.rb CHANGED
@@ -46,6 +46,18 @@ module Sisimai
46
46
  RFC822Head = Sisimai::RFC5322.HEADERFIELDS(:all)
47
47
  ActionList = { delayed: 1, delivered: 1, expanded: 1, failed: 1, relayed: 1 };
48
48
 
49
+ if RUBY_PLATFORM.start_with?('java')
50
+ # [WORKAROUND] #159 #267 JRuby seems to fail and throws exception at strptime(), but this
51
+ # issue might be fixed in a future version of JRuby.
52
+ # https://gist.github.com/hiroyuki-sato/6ef40245874d4c847a95ef99886e4fa7
53
+ # https://github.com/sisimai/rb-sisimai/issues/267#issuecomment-1976642884
54
+ # https://github.com/jruby/jruby/issues/8139
55
+ # https://github.com/sisimai/rb-sisimai/issues/267
56
+ TimeModule = ::DateTime
57
+ else
58
+ TimeModule = Sisimai::Time
59
+ end
60
+
49
61
  # Constructor of Sisimai::Fact
50
62
  # @param [Hash] argvs Including each parameter
51
63
  # @return [Sisimai::Fact] Structured email data
@@ -188,7 +200,7 @@ module Sisimai
188
200
 
189
201
  begin
190
202
  # Convert from the date string to an object then calculate time zone offset.
191
- t = Sisimai::Time.strptime(datestring, '%a, %d %b %Y %T')
203
+ t = TimeModule.strptime(datestring, '%a, %d %b %Y %T')
192
204
  p['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
193
205
  rescue
194
206
  warn ' ***warning: Failed to strptime ' << datestring.to_s
@@ -196,12 +208,12 @@ module Sisimai
196
208
  next unless p['timestamp']
197
209
 
198
210
  # OTHER_TEXT_HEADERS:
199
- recvheader = mesg1['header']['received'] || []
200
- unless recvheader.empty?
201
- # Get localhost and remote host name from Received header.
202
- %w[lhost rhost].each { |a| e[a] ||= '' }
203
- e['lhost'] = Sisimai::RFC5322.received(recvheader[0]).shift if e['lhost'].empty?
204
- e['rhost'] = Sisimai::RFC5322.received(recvheader[-1]).pop if e['rhost'].empty?
211
+ rr = mesg1['header']['received'] || []
212
+ unless rr.empty?
213
+ # Get a localhost and a remote host name from Received header.
214
+ p['rhost'] = Sisimai::RFC5322.received(rr[-1])[1] if p['rhost'].empty?
215
+ p['lhost'] = '' if p['rhost'] == p['lhost']
216
+ p['lhost'] = Sisimai::RFC5322.received(rr[ 0])[0] if p['lhost'].empty?
205
217
  end
206
218
 
207
219
  # Remove square brackets and curly brackets from the host variable
@@ -339,9 +351,35 @@ module Sisimai
339
351
  o['catch'] = p['catch'] || nil
340
352
  o['hardbounce'] = p['hardbounce']
341
353
  o['replycode'] = Sisimai::SMTP::Reply.find(p['diagnosticcode']).to_s if o['replycode'].empty?
342
- o['timestamp'] = Sisimai::Time.parse(::Time.at(p['timestamp']).to_s)
354
+ o['timestamp'] = TimeModule.parse(::Time.at(p['timestamp']).to_s)
343
355
  o['timezoneoffset'] = p['timezoneoffset'] || '+0000'
344
356
 
357
+ # ALIAS
358
+ while true do
359
+ # Look up the Envelope-To address from the Received: header in the original message
360
+ # when the recipient address is same with the value of o['alias'].
361
+ break if o['alias'].empty?
362
+ break if o['recipient'].address != o['alias']
363
+ break unless rfc822data.has_key?('received')
364
+ break if rfc822data['received'].empty?
365
+
366
+ rfc822data['received'].reverse.each do |er|
367
+ # Search for the string " for " from the Received: header
368
+ next unless er.include?(' for ')
369
+
370
+ af = Sisimai::RFC5322.received(er)
371
+ next if af.empty?
372
+ next if af[5].empty?
373
+ next unless Sisimai::Address.is_emailaddress(af[5])
374
+ next if o['recipient'].address == af[5]
375
+
376
+ o['alias'] = af[5]
377
+ break
378
+ end
379
+ break
380
+ end
381
+ o['alias'] = '' if o['alias'] == o['recipient'].address
382
+
345
383
  # REASON: Decide the reason of email bounce
346
384
  if o['reason'].empty? || RetryIndex[o['reason']]
347
385
  # The value of "reason" is empty or is needed to check with other values again
@@ -305,7 +305,6 @@ module Sisimai::Lhost
305
305
 
306
306
  dscontents.each do |e|
307
307
  # Set default values if each value is empty.
308
- e['lhost'] ||= permessage['rhost']
309
308
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
310
309
 
311
310
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].to_s.tr("\n", ' '))
@@ -98,7 +98,6 @@ module Sisimai::Lhost
98
98
 
99
99
  dscontents.each do |e|
100
100
  # Set default values if each value is empty.
101
- e['lhost'] ||= permessage['rhost']
102
101
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
103
102
 
104
103
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -100,7 +100,6 @@ module Sisimai::Lhost
100
100
 
101
101
  dscontents.each do |e|
102
102
  # Set default values if each value is empty.
103
- e['lhost'] ||= permessage['rhost']
104
103
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
105
104
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].tr("\n", ' '))
106
105
 
@@ -108,7 +108,6 @@ module Sisimai::Lhost
108
108
 
109
109
  dscontents.each do |e|
110
110
  # Set default values if each value is empty.
111
- e['lhost'] ||= permessage['rhost']
112
111
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
113
112
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
114
113
  e['command'] = thecommand || ''
@@ -123,7 +123,6 @@ module Sisimai::Lhost
123
123
  dscontents.each do |e|
124
124
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
125
125
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
126
- e['lhost'] ||= permessage['rhost']
127
126
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
128
127
 
129
128
  MessagesOf.each_key do |r|
@@ -147,7 +147,7 @@ module Sisimai::Lhost
147
147
  next unless p > 0
148
148
 
149
149
  # #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ##
150
- f = e['diagnosis'][p + 1, e['diagnosis'].index(';') - p -1]
150
+ f = e['diagnosis'][p + 1, e['diagnosis'].index(';') - p - 1]
151
151
  NDRSubject.each_key do |r|
152
152
  # Try to match with error subject strings
153
153
  next unless f == r
@@ -147,7 +147,6 @@ module Sisimai::Lhost
147
147
  readcursor = 0 # (Integer) Points the current cursor position
148
148
  nextcursor = 0
149
149
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
150
- localhost0 = '' # (String) Local MTA
151
150
  boundary00 = '' # (String) Boundary string
152
151
  v = nil
153
152
 
@@ -342,18 +341,13 @@ module Sisimai::Lhost
342
341
  end
343
342
  return nil unless recipients > 0
344
343
 
345
- unless mhead['received'].empty?
346
- # Get the name of local MTA
347
- # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
348
- p1 = mhead['received'][-1].index('from ') || -1
349
- p2 = mhead['received'][-1].index(' ', p1 + 5) || -1
350
- localhost0 = mhead['received'][-1][p1 + 5, p2 - p1 - 5] if p1 > -1 && p2 > -1
351
- end
344
+ # Get the name of the local MTA
345
+ # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
346
+ receivedby = mhead['received'] || []
347
+ recvdtoken = Sisimai::RFC5322.received(receivedby[-1])
352
348
 
353
349
  dscontents.each do |e|
354
- # Set default values if each value is empty.
355
- e['lhost'] ||= localhost0
356
-
350
+ # Check the error message, the rhost, the lhost, and the smtp command.
357
351
  unless e['diagnosis']
358
352
  # Empty Diagnostic-Code: or error message
359
353
  unless boundary00.empty?
@@ -405,12 +399,9 @@ module Sisimai::Lhost
405
399
  p1 = e['diagnosis'].index('host ') || -1
406
400
  p2 = e['diagnosis'].index(' ', p1 + 5) || -1
407
401
  e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
408
-
409
- unless e['rhost']
410
- # Get localhost and remote host name from Received header.
411
- e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop unless mhead['received'].empty?
412
- end
402
+ e['rhost'] ||= recvdtoken[1]
413
403
  end
404
+ e['lhost'] ||= recvdtoken[0]
414
405
 
415
406
  unless e['command']
416
407
  # Get the SMTP command name for the session
@@ -146,7 +146,6 @@ module Sisimai::Lhost
146
146
  return nil unless recipients > 0
147
147
 
148
148
  dscontents.each do |e|
149
- e['lhost'] ||= permessage['lhost']
150
149
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
151
150
 
152
151
  p0 = e['diagnosis'].index('-') || -1
@@ -48,9 +48,10 @@ module Sisimai::Lhost
48
48
  # * You may need to join the group before receiving permission to post.
49
49
  # * This group may not be open to posting.
50
50
  entiremesg = emailparts[0].split(/\n\n/, 5).slice(0, 4).join(' ').tr("\n", ' ');
51
+ receivedby = mhead['received'] || []
51
52
  recordwide['diagnosis'] = Sisimai::String.sweep(entiremesg)
52
53
  recordwide['reason'] = emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4 ? 'rejected' : 'onhold'
53
- recordwide['rhost'] = Sisimai::RFC5322.received(mhead['received'][0]).shift
54
+ recordwide['rhost'] = Sisimai::RFC5322.received(receivedby[0])[1]
54
55
 
55
56
  mhead['x-failed-recipients'].split(',').each do |e|
56
57
  # X-Failed-Recipients: neko@example.jp, nyaan@example.org, ...
@@ -135,7 +135,6 @@ module Sisimai::Lhost
135
135
 
136
136
  dscontents.each do |e|
137
137
  # Set default values if each value is empty.
138
- e['lhost'] ||= permessage['rhost']
139
138
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
140
139
 
141
140
  if anotherset['diagnosis']
@@ -42,7 +42,7 @@ module Sisimai::Lhost
42
42
 
43
43
  # Your message:
44
44
  # From: originalsender@example.com
45
- # Subject: IIdentifica蟾ス驕俳
45
+ # Subject: ...
46
46
  #
47
47
  # Could not be delivered because of
48
48
  #