sisimai 4.25.17 → 5.0.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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/ANALYTICAL-PRECISION +2 -2
  4. data/Benchmarks.mk +3 -3
  5. data/CONTRIBUTING +1 -1
  6. data/ChangeLog.md +406 -407
  7. data/Developers.mk +5 -6
  8. data/Gemfile +1 -1
  9. data/Makefile +12 -12
  10. data/README-JA.md +142 -94
  11. data/README.md +282 -150
  12. data/Rakefile +9 -3
  13. data/Repository.mk +2 -3
  14. data/lib/sisimai/address.rb +118 -74
  15. data/lib/sisimai/arf.rb +84 -82
  16. data/lib/sisimai/datetime.rb +5 -52
  17. data/lib/sisimai/{data → fact}/json.rb +7 -9
  18. data/lib/sisimai/fact/yaml.rb +31 -0
  19. data/lib/sisimai/fact.rb +468 -0
  20. data/lib/sisimai/lhost/activehunter.rb +12 -14
  21. data/lib/sisimai/lhost/amavis.rb +11 -14
  22. data/lib/sisimai/lhost/amazonses.rb +37 -41
  23. data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
  24. data/lib/sisimai/lhost/aol.rb +12 -14
  25. data/lib/sisimai/lhost/apachejames.rb +19 -21
  26. data/lib/sisimai/lhost/barracuda.rb +10 -12
  27. data/lib/sisimai/lhost/bigfoot.rb +21 -21
  28. data/lib/sisimai/lhost/biglobe.rb +15 -16
  29. data/lib/sisimai/lhost/courier.rb +20 -20
  30. data/lib/sisimai/lhost/domino.rb +23 -19
  31. data/lib/sisimai/lhost/einsundeins.rb +20 -16
  32. data/lib/sisimai/lhost/exchange2003.rb +30 -29
  33. data/lib/sisimai/lhost/exchange2007.rb +70 -58
  34. data/lib/sisimai/lhost/exim.rb +175 -161
  35. data/lib/sisimai/lhost/ezweb.rb +31 -56
  36. data/lib/sisimai/lhost/facebook.rb +21 -33
  37. data/lib/sisimai/lhost/fml.rb +43 -48
  38. data/lib/sisimai/lhost/gmail.rb +29 -29
  39. data/lib/sisimai/lhost/gmx.rb +18 -17
  40. data/lib/sisimai/lhost/googlegroups.rb +9 -10
  41. data/lib/sisimai/lhost/gsuite.rb +21 -27
  42. data/lib/sisimai/lhost/imailserver.rb +25 -39
  43. data/lib/sisimai/lhost/interscanmss.rb +28 -31
  44. data/lib/sisimai/lhost/kddi.rb +22 -28
  45. data/lib/sisimai/lhost/mailfoundry.rb +11 -12
  46. data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
  47. data/lib/sisimai/lhost/mailru.rb +33 -27
  48. data/lib/sisimai/lhost/mcafee.rb +21 -31
  49. data/lib/sisimai/lhost/messagelabs.rb +17 -20
  50. data/lib/sisimai/lhost/messagingserver.rb +40 -37
  51. data/lib/sisimai/lhost/mfilter.rb +15 -16
  52. data/lib/sisimai/lhost/mxlogic.rb +24 -23
  53. data/lib/sisimai/lhost/notes.rb +17 -17
  54. data/lib/sisimai/lhost/office365.rb +63 -27
  55. data/lib/sisimai/lhost/opensmtpd.rb +12 -13
  56. data/lib/sisimai/lhost/outlook.rb +12 -15
  57. data/lib/sisimai/lhost/postfix.rb +179 -129
  58. data/lib/sisimai/lhost/powermta.rb +12 -14
  59. data/lib/sisimai/lhost/qmail.rb +44 -47
  60. data/lib/sisimai/lhost/receivingses.rb +15 -20
  61. data/lib/sisimai/lhost/sendgrid.rb +34 -32
  62. data/lib/sisimai/lhost/sendmail.rb +66 -53
  63. data/lib/sisimai/lhost/surfcontrol.rb +19 -19
  64. data/lib/sisimai/lhost/v5sendmail.rb +45 -39
  65. data/lib/sisimai/lhost/verizon.rb +35 -39
  66. data/lib/sisimai/lhost/x1.rb +18 -17
  67. data/lib/sisimai/lhost/x2.rb +17 -14
  68. data/lib/sisimai/lhost/x3.rb +19 -19
  69. data/lib/sisimai/lhost/x4.rb +72 -57
  70. data/lib/sisimai/lhost/x5.rb +17 -19
  71. data/lib/sisimai/lhost/x6.rb +41 -17
  72. data/lib/sisimai/lhost/yahoo.rb +17 -16
  73. data/lib/sisimai/lhost/yandex.rb +16 -20
  74. data/lib/sisimai/lhost/zoho.rb +16 -15
  75. data/lib/sisimai/lhost.rb +8 -10
  76. data/lib/sisimai/mail/maildir.rb +1 -3
  77. data/lib/sisimai/mail/mbox.rb +3 -4
  78. data/lib/sisimai/mail/memory.rb +0 -1
  79. data/lib/sisimai/mail/stdin.rb +1 -3
  80. data/lib/sisimai/mail.rb +3 -7
  81. data/lib/sisimai/mda.rb +28 -42
  82. data/lib/sisimai/message.rb +435 -325
  83. data/lib/sisimai/order.rb +5 -5
  84. data/lib/sisimai/reason/authfailure.rb +64 -0
  85. data/lib/sisimai/reason/badreputation.rb +53 -0
  86. data/lib/sisimai/reason/blocked.rb +94 -160
  87. data/lib/sisimai/reason/contenterror.rb +8 -9
  88. data/lib/sisimai/reason/delivered.rb +4 -6
  89. data/lib/sisimai/reason/exceedlimit.rb +10 -12
  90. data/lib/sisimai/reason/expired.rb +6 -8
  91. data/lib/sisimai/reason/feedback.rb +2 -3
  92. data/lib/sisimai/reason/filtered.rb +17 -19
  93. data/lib/sisimai/reason/hasmoved.rb +9 -10
  94. data/lib/sisimai/reason/hostunknown.rb +15 -15
  95. data/lib/sisimai/reason/mailboxfull.rb +10 -12
  96. data/lib/sisimai/reason/mailererror.rb +18 -20
  97. data/lib/sisimai/reason/mesgtoobig.rb +9 -11
  98. data/lib/sisimai/reason/networkerror.rb +5 -8
  99. data/lib/sisimai/reason/norelaying.rb +8 -11
  100. data/lib/sisimai/reason/notaccept.rb +13 -14
  101. data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
  102. data/lib/sisimai/reason/onhold.rb +6 -9
  103. data/lib/sisimai/reason/policyviolation.rb +14 -12
  104. data/lib/sisimai/reason/rejected.rb +26 -24
  105. data/lib/sisimai/reason/requireptr.rb +69 -0
  106. data/lib/sisimai/reason/securityerror.rb +33 -36
  107. data/lib/sisimai/reason/spamdetected.rb +114 -147
  108. data/lib/sisimai/reason/speeding.rb +49 -0
  109. data/lib/sisimai/reason/suspend.rb +11 -11
  110. data/lib/sisimai/reason/syntaxerror.rb +11 -10
  111. data/lib/sisimai/reason/systemerror.rb +7 -9
  112. data/lib/sisimai/reason/systemfull.rb +7 -8
  113. data/lib/sisimai/reason/toomanyconn.rb +9 -11
  114. data/lib/sisimai/reason/undefined.rb +2 -3
  115. data/lib/sisimai/reason/userunknown.rb +129 -146
  116. data/lib/sisimai/reason/vacation.rb +3 -4
  117. data/lib/sisimai/reason/virusdetected.rb +10 -11
  118. data/lib/sisimai/reason.rb +59 -64
  119. data/lib/sisimai/rfc1894.rb +55 -28
  120. data/lib/sisimai/rfc2045.rb +373 -0
  121. data/lib/sisimai/rfc3464.rb +250 -308
  122. data/lib/sisimai/rfc3834.rb +42 -45
  123. data/lib/sisimai/rfc5322.rb +75 -100
  124. data/lib/sisimai/rfc5965.rb +31 -0
  125. data/lib/sisimai/rhost/cox.rb +5 -6
  126. data/lib/sisimai/rhost/franceptt.rb +6 -8
  127. data/lib/sisimai/rhost/godaddy.rb +12 -12
  128. data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
  129. data/lib/sisimai/rhost/iua.rb +9 -10
  130. data/lib/sisimai/rhost/kddi.rb +6 -8
  131. data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
  132. data/lib/sisimai/rhost/mimecast.rb +42 -40
  133. data/lib/sisimai/rhost/nttdocomo.rb +13 -18
  134. data/lib/sisimai/rhost/spectrum.rb +10 -12
  135. data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
  136. data/lib/sisimai/rhost.rb +23 -31
  137. data/lib/sisimai/smtp/command.rb +59 -0
  138. data/lib/sisimai/smtp/error.rb +4 -7
  139. data/lib/sisimai/smtp/reply.rb +161 -74
  140. data/lib/sisimai/smtp/status.rb +504 -393
  141. data/lib/sisimai/smtp/transcript.rb +124 -0
  142. data/lib/sisimai/smtp.rb +0 -1
  143. data/lib/sisimai/string.rb +74 -5
  144. data/lib/sisimai/time.rb +1 -2
  145. data/lib/sisimai/version.rb +1 -1
  146. data/lib/sisimai.rb +35 -21
  147. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
  148. data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
  149. data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
  150. data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
  151. data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
  152. data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
  153. data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
  154. data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
  155. data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
  156. data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
  157. data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
  158. data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
  159. data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
  160. data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
  161. data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
  162. data/sisimai-java.gemspec +1 -1
  163. data/sisimai.gemspec +1 -1
  164. metadata +41 -21
  165. data/.rspec +0 -2
  166. data/lib/sisimai/data/yaml.rb +0 -33
  167. data/lib/sisimai/data.rb +0 -411
  168. data/lib/sisimai/mime.rb +0 -456
  169. data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
  170. /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
  171. /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
  172. /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
  177. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
  178. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
data/README.md CHANGED
@@ -1,28 +1,28 @@
1
1
  ![](https://libsisimai.org/static/images/logo/sisimai-x01.png)
2
-
3
2
  [![License](https://img.shields.io/badge/license-BSD%202--Clause-orange.svg)](https://github.com/sisimai/rb-sisimai/blob/master/LICENSE)
4
3
  [![Coverage Status](https://img.shields.io/coveralls/sisimai/rb-sisimai.svg)](https://coveralls.io/r/sisimai/rb-sisimai)
5
- [![Ruby](https://img.shields.io/badge/ruby-v2.1.0--v3.3.0-red.svg)](https://www.ruby-lang.org/)
4
+ [![Ruby](https://img.shields.io/badge/ruby-v2.4.0--v2.7.0-red.svg)](https://www.ruby-lang.org/)
6
5
  [![Gem Version](https://badge.fury.io/rb/sisimai.svg)](https://badge.fury.io/rb/sisimai)
7
6
 
8
7
  > [!IMPORTANT]
9
8
  > **The default branch of this repository is [5-stable](https://github.com/sisimai/rb-sisimai/tree/5-stable)
10
9
  > (Sisimai 5) since 2nd February 2024.**
11
- > If you want to clone the old version, see the [4-stable](https://github.com/sisimai/rb-sisimai/tree/4-stable)
10
+ > If you want to clone the old version, see the [4-stable](https://github.com/sisimai/rb-sisimai/tree/4-stable)[^1]
12
11
  > branch instead. We have moved away from using both the `main` and `master` branches in our development process.
13
-
14
- > [!CAUTION]
15
- > **Sisimai versions 4.25.14p11 and earlier contain a regular expression vulnerability
16
- > [ReDoS: CVE-2022-4891](https://nvd.nist.gov/vuln/detail/CVE-2022-4891).
17
- > If you are using one of these versions, please upgrade to v4.25.14p12 or later.**
12
+ [^1]: Specify `-b 4-stable` when you clone Sisimai 4 for example, `git clone -b 4-stable https://github.com/sisimai/rb-sisimai.git`
18
13
 
19
14
  > [!WARNING]
20
15
  > Sisimai 5 requires Ruby 2.4 or later. Check the version of Ruby in your system before installing/upgrading
21
16
  > by `ruby -v` command.
22
17
 
18
+ > [!CAUTION]
19
+ > [Sisimai 5](https://github.com/sisimai/rb-sisimai/releases/tag/v5.0.0) has not been uploaded to
20
+ > [RubyGems.org](https://rubygems.org/gems/sisimai) yet as of February 2nd. It will be available on
21
+ > RubyGems.org within a few months, but until then, please clone it from this repository.
22
+
23
23
  - [**README-JA(日本語)**](README-JA.md)
24
24
  - [What is Sisimai](#what-is-sisimai)
25
- - [Key features](#key-features)
25
+ - [The key features of sisimai](#the-key-features-of-sisimai)
26
26
  - [Command line demo](#command-line-demo)
27
27
  - [Setting Up Sisimai](#setting-up-sisimai)
28
28
  - [System requirements](#system-requirements)
@@ -35,12 +35,14 @@
35
35
  - [Callback feature](#callback-feature)
36
36
  - [One-Liner](#one-liner)
37
37
  - [Output example](#output-example)
38
- - [Sisimai Specification](#sisimai-specification)
39
- - [Differences between Ruby version and Perl version](#differences-between-ruby-version-and-perl-version)
40
- - [Other specification of Sisimai](#other-specification-of-sisimai)
38
+ - [Differences between Sisimai 4 and Sisimai 5](#differences-between-sisimai-4-and-sisimai-5)
39
+ - [Features](#features)
40
+ - [Decoding Methods](#decoding-methods)
41
+ - [MTA/ESP Module Names](#mtaesp-module-names)
42
+ - [Bounce Reasons](#bounce-reasons)
41
43
  - [Contributing](#contributing)
42
44
  - [Bug report](#bug-report)
43
- - [Emails could not be parsed](#emails-could-not-be-parsed)
45
+ - [Emails could not be decoded](#emails-could-not-be-decoded)
44
46
  - [Other Information](#other-information)
45
47
  - [Related sites](#related-sites)
46
48
  - [See also](#see-also)
@@ -49,112 +51,151 @@
49
51
  - [License](#license)
50
52
 
51
53
  What is Sisimai
52
- ===============================================================================
53
- Sisimai is a Ruby library for analyzing RFC5322 bounce emails and generating
54
- structured data from parsed results. The Ruby version of Sisimai is ported from
55
- the Perl version of Sisimai at [github.com/sisimai/p5-sisimai](https://github.com/sisimai/p5-sisimai/).
54
+ ===================================================================================================
55
+ Sisimai is a library that decodes complex and diverse bounce emails and outputs the results of the
56
+ delivery failure, such as the reason for the bounce and the recipient email address, in structured
57
+ data. It is also possible to output in JSON format. The Ruby version of Sisimai is ported from the
58
+ Perl version of Sisimai at [github.com/sisimai/p5-sisimai](https://github.com/sisimai/p5-sisimai/).
56
59
 
57
60
  ![](https://libsisimai.org/static/images/figure/sisimai-overview-1.png)
58
61
 
59
- Key Features
60
- -------------------------------------------------------------------------------
61
- * __Convert Bounce Mails to Structured Data__
62
- * Supported formats are Ruby(Hash, Array) and JSON(String)
63
- * __Easy to Install, Use.__
64
- * gem install
65
- * git clone & make
66
- * __High Precision of Analysis__
67
- * 2 times higher than bounceHammer
68
- * Support 68 MTAs/MDAs/ESPs
69
- * Support Feedback Loop Message(ARF)
70
- * Can detect 29 error reasons
62
+ The key features of Sisimai
63
+ ---------------------------------------------------------------------------------------------------
64
+ * __Decode email bounces to structured data__
65
+ * Sisimai provides detailed insights into bounce emails by extracting 24 key data points.[^2]
66
+ * __Essential information__: `timestamp`, `origin`
67
+ * __Sender information__: `addresser`, `senderdomain`,
68
+ * __Recipient information__: `recipient`, `destination`, `alias`
69
+ * __Delivery information__: `action`, `replycode`,`action`, `replycode`, `deliverystatus`
70
+ * __Bounce details__: `reason`, `diagnosticcode`, `diagnostictype`, `feedbacktype`, `hardbounce`
71
+ * __Message details__: `subject`, `messageid`, `listid`,
72
+ * __Additional information__: `smtpagent`, `timezoneoffset`, `lhost`, `rhost`, `token`, `catch`
73
+ * Output formats
74
+ * Ruby (Hash, Array)
75
+ * JSON
76
+ * (by using [`oj`](https://rubygems.org/gems/oj) gem at CRuby)
77
+ * (by using [`jrjackson`](https://rubygems.org/gems/jrjackson) gem at JRuby)
78
+ * YAML ([`yaml`](https://rubygems.org/gems/yaml) gem required)
79
+ * __Easy to Install, Use.__
80
+ * `gem install`
81
+ * `git clone && make`
82
+ * __High Precision of Analysis__
83
+ * Support [70 MTAs/MDAs/ESPs](https://libsisimai.org/en/engine/)
84
+ * Support Feedback Loop Message(ARF)
85
+ * Can detect [34 bounce reasons](https://libsisimai.org/en/reason/)
86
+
87
+ [^2]: The callback function allows you to add your own data under the `catch` accessor.
71
88
 
72
89
  Command line demo
73
- -------------------------------------------------------------------------------
74
- The following screen shows a demonstration of Sisimai at the command line using
75
- Ruby(rb-sisimai) and Perl(p5-sisimai) version of Sisimai.
76
- ![](https://libsisimai.org/static/images/demo/sisimai-dump-01.gif)
90
+ ---------------------------------------------------------------------------------------------------
91
+ The following screen shows a demonstration of `dump` method of Sisimai 5 at the command line using
92
+ Ruby(rb-sisimai) and `jq` command.
93
+ ![](https://libsisimai.org/static/images/demo/sisimai-5-cli-dump-r01.gif)
77
94
 
78
95
  Setting Up Sisimai
79
- ===============================================================================
80
-
96
+ ===================================================================================================
81
97
  System requirements
82
- -------------------------------------------------------------------------------
98
+ ---------------------------------------------------------------------------------------------------
83
99
  More details about system requirements are available at
84
100
  [Sisimai | Getting Started](https://libsisimai.org/en/start/) page.
85
101
 
86
102
 
87
- * [Ruby 2.1.0 or later](http://www.ruby-lang.org/)
88
- * [__Oj | The fastest JSON parser and object serializer__](https://rubygems.org/gems/oj)
89
- * Also works on [JRuby 9.0.4.0 - 9.1.17.0](http://jruby.org)
90
- * [__JrJackson | A mostly native JRuby wrapper for the java jackson json processor jar__](https://rubygems.org/gems/jrjackson)
103
+ * [Ruby 2.4.0 or later](http://www.ruby-lang.org/)
104
+ * [__oj | The fastest JSON parser and object serializer__](https://rubygems.org/gems/oj)
105
+ * Also works on [JRuby 9.0.4.0 or later](http://jruby.org)
106
+ * [__jrjackson | A mostly native JRuby wrapper for the java jackson json processor jar__](https://rubygems.org/gems/jrjackson)
91
107
 
92
108
  Install
93
- -------------------------------------------------------------------------------
109
+ ---------------------------------------------------------------------------------------------------
94
110
  ### From RubyGems
111
+ > [!CAUTION]
112
+ > [Sisimai 5](https://github.com/sisimai/p5-sisimai/releases/tag/v5.0.0) has not been uploaded to
113
+ > [RubyGems.org](https://rubygems.org/gems/sisimai) yet as of February 2nd. It will be available on
114
+ > RubyGems.org within a few months, but until then, please clone it from this repository.
95
115
 
96
116
  ```shell
97
117
  $ sudo gem install sisimai
98
- Fetching: sisimai-4.25.17.gem (100%)
99
- Successfully installed sisimai-4.25.17
100
- Parsing documentation for sisimai-4.25.17
101
- Installing ri documentation for sisimai-4.25.17
118
+ Fetching: sisimai-4.25.16.gem (100%)
119
+ Successfully installed sisimai-4.25.16
120
+ Parsing documentation for sisimai-4.25.16
121
+ Installing ri documentation for sisimai-4.25.16
102
122
  Done installing documentation for sisimai after 6 seconds
103
123
  1 gem installed
104
124
  ```
105
125
 
106
126
  ### From GitHub
127
+ > [!WARNING]
128
+ > Sisimai 5 requires Ruby 2.4 or later. Check the version of Ruby in your system before installing/upgrading
129
+ > by `ruby -v` command.
107
130
 
108
131
  ```shell
132
+ % ruby -v
133
+ ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin21]
134
+
109
135
  $ cd /usr/local/src
110
136
  $ git clone https://github.com/sisimai/rb-sisimai.git
137
+
111
138
  $ cd ./rb-sisimai
112
139
  $ sudo make depend install-from-local
113
- gem install bundle rake rspec coveralls
140
+ gem install bundle rake minitest
114
141
  ...
115
- 4 gems installed
116
- bundle exec rake install
117
- sisimai 4.25.17 built to pkg/sisimai-4.25.17.gem.
118
- sisimai (4.25.17) installed.
142
+ 3 gems installed
143
+ if [ -d "/usr/local/jr" ]; then \
144
+ PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/gem install bundle rake minitest; \
145
+ fi
146
+ ...
147
+ 3 gems installed
148
+ /opt/local/bin/rake install
149
+ sisimai 5.0.0 built to pkg/sisimai-5.0.0.gem.
150
+ sisimai (5.0.0) installed.
151
+ if [ -d "/usr/local/jr" ]; then \
152
+ PATH="/usr/local/jr/bin:$PATH" /usr/local/jr/bin/rake install; \
153
+ fi
154
+ sisimai 5.0.0 built to pkg/sisimai-5.0.0-java.gem.
155
+ sisimai (5.0.0) installed.
119
156
  ```
120
157
 
121
158
  Usage
122
- ===============================================================================
123
-
159
+ ===================================================================================================
124
160
  Basic usage
125
- -------------------------------------------------------------------------------
126
- `make()` method provides feature for getting parsed data from bounced email
127
- messages like following. Beginning with v4.25.6, new accessor `origin` which
128
- keeps the path to email file as a data source is available.
129
-
161
+ ---------------------------------------------------------------------------------------------------
162
+ `Sisimai->rise()` method provides the feature for getting decoded data as Ruby Hash from bounced
163
+ email messages as the following. Beginning with v4.25.6, new accessor `origin` which keeps the path
164
+ to email file as a data source is available.
130
165
 
131
166
  ```ruby
132
167
  #! /usr/bin/env ruby
133
168
  require 'sisimai'
134
- v = Sisimai.make('/path/to/mbox') # or path to Maildir/
169
+ v = Sisimai.rise('/path/to/mbox') # or path to Maildir/
135
170
 
136
- # Beginning with v4.23.0, both make() and dump() method of Sisimai class can
137
- # read bounce messages from variable instead of a path to mailbox
171
+ # In v4.23.0, the rise() and dump() methods of the Sisimai class can now read the entire bounce
172
+ # email as a string, in addition to the PATH to the email file or mailbox.
138
173
  f = File.open('/path/to/mbox', 'r'); # or path to Maildir/
139
- v = Sisimai.make(f.read)
174
+ v = Sisimai.rise(f.read)
140
175
 
141
- # If you want to get bounce records which reason is "delivered", set "delivered"
142
- # option to make() method like the following:
143
- v = Sisimai.make('/path/to/mbox', delivered: true)
176
+ # If you also need analysis results that are "delivered" (successfully delivered), please specify
177
+ # the "delivered" option to the rise() method as shown below.
178
+ v = Sisimai.rise('/path/to/mbox', delivered: true)
179
+
180
+ # From v5.0.0, Sisimai no longer returns analysis results with a bounce reason of "vacation" by
181
+ # default. If you also need analysis results that show a "vacation" reason, please specify the
182
+ # "vacation" option to the rise() method as shown in the following code.
183
+ v = Sisimai.rise('/path/to/mbox', vacation: true );
144
184
 
145
185
  if v.is_a? Array
146
186
  v.each do |e|
147
- puts e.class # Sisimai::Data
187
+ puts e.class # Sisimai::Fact
148
188
  puts e.recipient.class # Sisimai::Address
149
189
  puts e.timestamp.class # Sisimai::Time
150
190
 
151
- puts e.addresser.address # shironeko@example.org # From
152
- puts e.recipient.address # kijitora@example.jp # To
153
- puts e.recipient.host # example.jp
154
- puts e.deliverystatus # 5.1.1
155
- puts e.replycode # 550
156
- puts e.reason # userunknown
157
- puts e.origin # /var/spool/bounce/Maildir/new/1740074341.eml
191
+ puts e.addresser.address # "michitsuna@example.org" # From
192
+ puts e.recipient.address # "kijitora@example.jp" # To
193
+ puts e.recipient.host # "example.jp"
194
+ puts e.deliverystatus # "5.1.1"
195
+ puts e.replycode # "550"
196
+ puts e.reason # "userunknown"
197
+ puts e.origin # "/var/spool/bounce/Maildir/new/1740074341.eml"
198
+ puts e.hardbounce # true
158
199
 
159
200
  h = e.damn # Convert to HASH
160
201
  j = e.dump('json') # Convert to JSON string
@@ -164,127 +205,218 @@ end
164
205
  ```
165
206
 
166
207
  Convert to JSON
167
- -------------------------------------------------------------------------------
168
- `Sisimai.dump()` method provides feature for getting parsed data as JSON string
169
- from bounced email messages like following.
208
+ ---------------------------------------------------------------------------------------------------
209
+ `Sisimai.dump()` method provides the feature for getting decoded data as JSON string from bounced
210
+ email messages like the following code:
170
211
 
171
212
  ```ruby
172
- # Get JSON string from parsed mailbox or Maildir/
213
+ # Get JSON string from path of a mailbox or a Maildir/
173
214
  puts Sisimai.dump('/path/to/mbox') # or path to Maildir/
174
215
 
175
- # dump() method also accepts "delivered" option like the following code:
176
- puts Sisimai.dump('/path/to/mbox', delivered: true)
216
+ # dump() method also accepts "delivered" and "vacation" option like the following code:
217
+ puts Sisimai.dump('/path/to/mbox', delivered: true, vacation: true)
177
218
  ```
178
219
 
179
220
  Callback feature
180
- -------------------------------------------------------------------------------
181
- Beginning with Sisimai 4.19.0, `make()` and `dump()` methods of Sisimai accept
182
- a Lambda (Proc object) in `hook` argument for setting a callback method and
183
- getting the results generated by the method via `Sisimai::Data.catch` method.
221
+ ---------------------------------------------------------------------------------------------------
222
+ `:c___` (`c` and three `_`s, looks like a fishhook) argument of `Sisimai.rise` and `Sisimai.dump`
223
+ is an Array and is a parameter to receive Proc objects for callback feature. The first element of
224
+ `:c___` argument is called at `Sisimai::Message.sift` for dealing email headers and entire message
225
+ body. The second element of `:c___` argument is called at the end of each email file parsing. The
226
+ result generated by the callback method is accessible via `Sisimai::Fact.catch`.
227
+
228
+ ### [0] For email headers and the body
229
+ Callback method set in the first element of `:c___` is called at `Sisimai::Message.sift()`.
184
230
 
185
231
  ```ruby
186
232
  #! /usr/bin/env ruby
187
233
  require 'sisimai'
188
- callbackto = lambda do |v|
189
- r = { 'x-mailer' => '', 'queue-id' => '' }
234
+ code = lambda do |args|
235
+ head = args['headers'] # (*Hash) Email headers
236
+ body = args['message'] # (String) Message body
237
+ adds = { 'x-mailer' => '', 'queue-id' => '' }
238
+
239
+ if cv = body.match(/^X-Postfix-Queue-ID:\s*(.+)$/)
240
+ adds['queue-id'] = cv[1]
241
+ end
242
+ r['x-mailer'] = head['x-mailer'] || ''
243
+ return adds
244
+ end
245
+
246
+ data = Sisimai.rise('/path/to/mbox', c___: [code, nil])
247
+ json = Sisimai.dump('/path/to/mbox', c___: [code, nil])
248
+
249
+ puts data[0].catch['x-mailer'] # "Apple Mail (2.1283)"
250
+ puts data[0].catch['queue-id'] # "43f4KX6WR7z1xcMG"
251
+ ```
252
+
253
+ ### For each email file
254
+ Callback method set in the second element of `:c___` is called at `Sisimai.rise` method for dealing
255
+ each email file.
190
256
 
191
- if cv = v['message'].match(/^X-Postfix-Queue-ID:\s*(.+)$/)
192
- r['queue-id'] = cv[1]
257
+ ```ruby
258
+ path = '/path/to/maildir'
259
+ code = lambda do |args|
260
+ kind = args['kind'] # (String) Sisimai::Mail.kind
261
+ mail = args['mail'] # (String) Entire email message
262
+ path = args['path'] # (String) Sisimai::Mail.path
263
+ sisi = args['sisi'] # (Array) List of Sisimai::Fact
264
+
265
+ sisi.each do |e|
266
+ # Store custom information in the "catch" accessor
267
+ e.catch ||= {}
268
+ e.catch['size'] = mail.size
269
+ e.catch['kind'] = kind.capitalize
270
+
271
+ if cv = mail.match(/^Return-Path: (.+)$/)
272
+ # Return-Path: <MAILER-DAEMON>
273
+ e.catch['return-path'] = cv[1]
274
+ end
275
+ e.catch['parsedat'] = Time.new.localtime.to_s
276
+
277
+ # Save the original email with an additional "X-Sisimai-Parsed:" header to a different PATH.
278
+ a = sprintf("X-Sisimai-Parsed: %d", sisi.size)
279
+ p = sprintf("/path/to/another/directory/sisimai-%s.eml", e.token)
280
+ v = mail.sub(/^(From:.+?)$/, '\1' + "\n" + a)
281
+ f = File.open(p, 'w:UTF-8')
282
+ f.write(v)
283
+ f.close
284
+
285
+ # Remove the email file in Maildir/ after decoding
286
+ File.delete(path) if kind == 'maildir'
287
+
288
+ # Need to not return a value
193
289
  end
194
- r['x-mailer'] = v['headers']['x-mailer'] || ''
195
- return r
196
290
  end
197
291
 
198
- data = Sisimai.make('/path/to/mbox', hook: callbackto)
199
- json = Sisimai.dump('/path/to/mbox', hook: callbackto)
292
+ list = Sisimai.rise(path, c___: [nil, code])
200
293
 
201
- puts data[0].catch['x-mailer'] # Apple Mail (2.1283)
294
+ puts list[0].catch['size'] # 2202
295
+ puts list[0].catch['kind'] # "Maildir"
296
+ puts list[0].catch['return-path'] # "<MAILER-DAEMON>"
202
297
  ```
203
298
 
204
299
  More information about the callback feature is available at
205
- [Sisimai | How To Parse - Callback](https://libsisimai.org/en/usage/#callback)
206
- Page.
300
+ [Sisimai | How To Parse - Callback](https://libsisimai.org/en/usage/#callback) Page.
207
301
 
208
302
  One-Liner
209
- -------------------------------------------------------------------------------
210
-
303
+ ---------------------------------------------------------------------------------------------------
211
304
  ```shell
212
305
  % ruby -rsisimai -e 'puts Sisimai.dump($*.shift)' /path/to/mbox
213
306
  ```
214
307
 
215
308
  Output example
216
- -------------------------------------------------------------------------------
217
- ![](https://libsisimai.org/static/images/demo/sisimai-dump-02.gif)
309
+ ---------------------------------------------------------------------------------------------------
310
+ ![](https://libsisimai.org/static/images/demo/sisimai-5-cli-dump-p01.gif)
218
311
 
219
312
  ```json
220
- [{"catch":{"x-mailer":"","return-path":"<shironeko@mx.example.co.jp>"},"token":"cf17945938502bd876603a375f0e9517c921bbab","lhost":"localhost","rhost":"mx-s.neko.example.jp","alias":"","listid":"","reason":"hasmoved","action":"failed","origin":"set-of-emails/maildir/bsd/lhost-sendmail-22.eml","subject":"Nyaaaan","messageid":"0000000011111.fff0000000003@mx.example.co.jp","replycode":"","smtpagent":"Sendmail","softbounce":0,"smtpcommand":"DATA","destination":"example.net","senderdomain":"example.co.jp","feedbacktype":"","diagnosticcode":"450 busy - please try later 551 not our customer 503 need RCPT command [data]","diagnostictype":"SMTP","deliverystatus":"5.1.6","timezoneoffset":"+0900","addresser":"shironeko@example.co.jp","recipient":"kijitora@example.net","timestamp":1397054085}]
313
+ [{"destination":"google.example.com","lhost":"gmail-smtp-in.l.google.com","hardbounce":0,"reason":"authfailure","catch":null,"addresser":"michitsuna@example.jp","alias":"nekochan@example.co.jp","smtpagent":"Postfix","smtpcommand":"DATA","senderdomain":"example.jp","listid":"","action":"failed","feedbacktype":"","messageid":"hwK7pzjzJtz0RF9Y@relay3.example.com","origin":"./gmail-5.7.26.eml","recipient":"kijitora@google.example.com","rhost":"gmail-smtp-in.l.google.com","subject":"Nyaan","timezoneoffset":"+0900","replycode":550,"token":"84656774898baa90660be3e12fe0526e108d4473","diagnostictype":"SMTP","timestamp":1650119685,"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)","deliverystatus":"5.7.26"}]
221
314
  ```
222
315
 
223
- Sisimai Specification
224
- ===============================================================================
225
-
226
- Differences between Ruby version and Perl version
227
- -------------------------------------------------------------------------------
228
- The following table show the differences between Ruby version of Sisimai
229
- and Perl version of Sisimai. Information about differences between Sisimai
230
- and bounceHammer are available at
231
- [Sisimai | Differences](https://libsisimai.org/en/diff/) page.
232
-
233
- | Features | Ruby version | Perl version |
234
- |---------------------------------------------|----------------|---------------|
235
- | System requirements | Ruby 2.1 - 3.3 | Perl 5.10 - |
236
- | | JRuby 9.0.4.0 | |
237
- | | - 9.1.17.0 | |
238
- | Analytical precision ratio(2000 emails)[1] | 1.00 | 1.00 |
239
- | The speed of parsing email(1000 emails) | 2.22s[2] | 1.35s |
240
- | How to install | gem install | cpanm, cpm |
241
- | Dependencies (Except core modules) | 1 module | 2 modules |
242
- | LOC:Source lines of code | 10600 lines | 10800 lines |
243
- | The number of tests(spec/,t/,xt/) directory | 241000 tests | 270000 tests |
244
- | License | BSD 2-Clause | BSD 2-Clause |
245
- | Support Contract provided by Developer | Available | Available |
246
-
247
- 1. See [./ANALYTICAL-PRECISION](https://github.com/sisimai/rb-sisimai/blob/master/ANALYTICAL-PRECISION)
248
- 2. Xeon E5-2640 2.5GHz x 2 cores | 5000 bogomips | 1GB RAM | Ruby 2.3.4p301
249
-
250
- Other specification of Sisimai
251
- -------------------------------------------------------------------------------
252
- - [**Parser Engines**](https://libsisimai.org/en/engine/)
253
- - [**Bounce Reason List**](https://libsisimai.org/en/reason/)
254
- - [**Data Structure of Sisimai::Data**](https://libsisimai.org/en/data/)
316
+ Differences between Sisimai 4 and Sisimai 5
317
+ ===================================================================================================
318
+ The following table show the differences between [Sisimai 4.25.16p1](https://github.com/sisimai/rb-sisimai/releases/tag/v4.25.16p1)
319
+ and [Sisimai 5](https://github.com/sisimai/rb-sisimai/releases/tag/v5.0.0). More information about
320
+ differences are available at [Sisimai | Differences](https://libsisimai.org/en/diff/) page.
321
+
322
+ Features
323
+ ---------------------------------------------------------------------------------------------------
324
+ Beginning with v5.0.0, Sisimai requires **Ruby 2.4.0 or later.**
325
+
326
+ | Features | Sisimai 4 | Sisimai 5 |
327
+ |------------------------------------------------------|--------------------|---------------------|
328
+ | System requirements (CRuby) | 2.1 - | **2.4** - 3.3.0 |
329
+ | System requirements (JRuby) | 9.0.4.0 - | 9.0.4.0 - |
330
+ | Callback feature for the original email file | N/A | Available[^3] |
331
+ | The number of MTA/ESP modules | 68 | 70 |
332
+ | The number of detectable bounce reasons | 29 | 34 |
333
+ | Dependencies (Except Ruby Standard Gems) | 1 gem | 1 gem |
334
+ | Source lines of code | 10,300 lines | 11,300 lines |
335
+ | The number of tests in spec/,test/ directory | 311,000 tests | 336,000 tests |
336
+ | The number of bounce emails decoded/sec (CRuby)[^4] | 231 emails | 305 emails |
337
+ | License | 2 Clause BSD | 2 Caluse BSD |
338
+ | Commercial support | Available | Available |
339
+
340
+ [^3]: The 2nd argument of `:c___` parameter at `Sisimai.rise` method
341
+ [^4]: macOS Monterey/1.6GHz Dual-Core Intel Core i5/16GB-RAM/Ruby 2.6.4p104
342
+
343
+
344
+ Decoding Method
345
+ ---------------------------------------------------------------------------------------------------
346
+ Some decoding method names, class names, parameter names have been changed at Sisimai 5.
347
+ The details of the decoded data are available at [LIBSISIMAI.ORG/EN/DATA](https://libsisimai.org/en/data/)
348
+
349
+ | Decoding Method | Sisimai 4 | Sisimai 5 |
350
+ |------------------------------------------------------|--------------------|---------------------|
351
+ | Decoding method name | `Sisimai.make` | `Sisimai.rise` |
352
+ | Dumping method name | `Sisimai.dump` | `Sisimai.dump` |
353
+ | Class name of decoded object | `Sisimai::Data` | `Sisimai::Fact` |
354
+ | Parameter name of the callback | `hook` | `:c___`[^5] |
355
+ | Method name for checking the hard/soft bounce | `softbounce` | `hardbounce` |
356
+ | Decode a vacation message by default | Yes | No |
357
+ | Sisimai::Message returns an object | Yes | No |
358
+ | MIME decoding class | `Sisimai::MIME` | `Sisimai::RFC2045` |
359
+ | Decoding transcript of SMTP session | No | Yes[^6] |
360
+
361
+ [^5]: `:c___` looks like a fishhook
362
+ [^6]: `Sisimai::SMTP::Transcript.rise` Method provides the feature
363
+
364
+
365
+ MTA/ESP Module Names
366
+ ---------------------------------------------------------------------------------------------------
367
+ Three ESP module names have been changed at Sisimai 5. The list of the all MTA/ESP modules is
368
+ available at [LIBSISIMAI.ORG/EN/ENGINE](https://libsisimai.org/en/engine/)
369
+
370
+ | `Sisimai::Rhost::` | Sisimai 4 | Sisimai 5 |
371
+ |------------------------------------------------------|--------------------|---------------------|
372
+ | Microsoft Exchange Online | `ExchangeOnline` | `Microsoft` |
373
+ | Google Workspace | `GoogleApps` | `Google` |
374
+ | Tencent | `TencentQQ` | `Tencent` |
375
+
376
+ Bounce Reasons
377
+ ---------------------------------------------------------------------------------------------------
378
+ Five bounce reasons have been added at Sisimai 5. The list of the all bounce reasons sisimai can
379
+ detect is available at [LIBSISIMAI.ORG/EN/REASON](https://libsisimai.org/en/reason/)
380
+
381
+ | Rejected due to | Sisimai 4 | Sisimai 5 |
382
+ |------------------------------------------------------|--------------------|---------------------|
383
+ | sender domain authentication(SPF,DKIM,DMARC) | `SecurityError` | `AuthFailure` |
384
+ | low/bad reputation of the sender hostname/IP addr. | `Blocked` | `BadReputation` |
385
+ | missing PTR/having invalid PTR | `Blocked` | `RequirePTR` |
386
+ | non-compliance with RFC[^7] | `SecurityError` | `NotCompliantRFC` |
387
+ | exceeding a rate limit or sending too fast | `SecurityError` | `Speeding` |
388
+
389
+ [^7]: RFC5322 and related RFCs
255
390
 
256
- Contributing
257
- ===============================================================================
258
391
 
392
+ Contributing
393
+ ===================================================================================================
259
394
  Bug report
260
- -------------------------------------------------------------------------------
261
- Please use the [issue tracker](https://github.com/sisimai/rb-sisimai/issues)
262
- to report any bugs.
395
+ ---------------------------------------------------------------------------------------------------
396
+ Please use the [issue tracker](https://github.com/sisimai/rb-sisimai/issues) to report any bugs.
263
397
 
264
- Emails could not be parsed
265
- -------------------------------------------------------------------------------
266
- Bounce mails which could not be parsed by Sisimai are saved in the repository
398
+ Emails could not be decoded
399
+ ---------------------------------------------------------------------------------------------------
400
+ Bounce mails which could not be decoded by Sisimai are saved in the repository
267
401
  [set-of-emails/to-be-debugged-because/sisimai-cannot-parse-yet](https://github.com/sisimai/set-of-emails/tree/master/to-be-debugged-because/sisimai-cannot-parse-yet).
268
- If you have found any bounce email cannot be parsed using Sisimai, please add
269
- the email into the directory and send Pull-Request to this repository.
402
+ If you have found any bounce email cannot be decoded using Sisimai, please add the email into the
403
+ directory and send Pull-Request to this repository.
270
404
 
271
405
  Other Information
272
- ===============================================================================
273
-
406
+ ===================================================================================================
274
407
  Related Sites
275
- -------------------------------------------------------------------------------
408
+ ---------------------------------------------------------------------------------------------------
276
409
  * __@libsisimai__ | [Sisimai on Twitter (@libsisimai)](https://twitter.com/libsisimai)
277
410
  * __LIBSISIMAI.ORG__ | [SISIMAI | MAIL ANALYZING INTERFACE | DECODING BOUNCES, BETTER AND FASTER.](https://libsisimai.org/)
278
411
  * __Sisimai Blog__ | [blog.libsisimai.org](http://blog.libsisimai.org/)
279
412
  * __Facebook Page__ | [facebook.com/libsisimai](https://www.facebook.com/libsisimai/)
280
413
  * __GitHub__ | [github.com/sisimai/rb-sisimai](https://github.com/sisimai/rb-sisimai)
281
414
  * __RubyGems.org__ | [rubygems.org/gems/sisimai](https://rubygems.org/gems/sisimai)
282
- * __Perl version__ | [Perl version of Sisimai](https://github.com/sisimai/p5-sisimai)
283
- * __Go version__ | [Go version of Sisimai 5](https://github.com/sisimai/go-sisimai)
415
+ * __Perl verson__ | [Perl version of Sisimai](https://github.com/sisimai/p5-sisimai)
284
416
  * __Fixtures__ | [set-of-emails - Sample emails for "make test"](https://github.com/sisimai/set-of-emails)
285
417
 
286
418
  See also
287
- -------------------------------------------------------------------------------
419
+ ---------------------------------------------------------------------------------------------------
288
420
  * [README-JA.md - README.md in Japanese(日本語)](https://github.com/sisimai/rb-sisimai/blob/master/README-JA.md)
289
421
  * [RFC3463 - Enhanced Mail System Status Codes](https://tools.ietf.org/html/rfc3463)
290
422
  * [RFC3464 - An Extensible Message Format for Delivery Status Notifications](https://tools.ietf.org/html/rfc3464)
@@ -293,14 +425,14 @@ See also
293
425
  * [RFC5322 - Internet Message Format](https://tools.ietf.org/html/rfc5322)
294
426
 
295
427
  Author
296
- ===============================================================================
428
+ ===================================================================================================
297
429
  [@azumakuniyuki](https://twitter.com/azumakuniyuki)
298
430
 
299
431
  Copyright
300
- ===============================================================================
301
- Copyright (C) 2015-2025 azumakuniyuki, All Rights Reserved.
432
+ ===================================================================================================
433
+ Copyright (C) 2015-2024 azumakuniyuki, All Rights Reserved.
302
434
 
303
435
  License
304
- ===============================================================================
436
+ ===================================================================================================
305
437
  This software is distributed under The BSD 2-Clause License.
306
438
 
data/Rakefile CHANGED
@@ -1,12 +1,18 @@
1
- require 'rspec/core/rake_task'
2
1
  require 'bundler/gem_helper'
2
+
3
3
  if RUBY_PLATFORM =~ /java/
4
4
  filename = 'sisimai-java'
5
5
  else
6
6
  filename = 'sisimai'
7
7
  end
8
8
  Bundler::GemHelper.install_tasks :name => filename
9
- RSpec::Core::RakeTask.new(:spec)
10
9
 
11
- task :default => :spec
10
+ task :default => :test
11
+ task :test => [:publictest, :privatetest]
12
+ task :publictest do
13
+ Dir.glob('./test/public/*-test.rb').each { |cf| require cf }
14
+ end
15
+ task :privatetest do
16
+ Dir.glob('./test/private/*-test.rb').each { |cf| require cf }
17
+ end
12
18
 
data/Repository.mk CHANGED
@@ -5,7 +5,7 @@
5
5
  # | _ < __/ |_) | (_) \__ \ | || (_) | | | |_| |_| | | | | | <
6
6
  # |_| \_\___| .__/ \___/|___/_|\__\___/|_| \__, (_)_| |_| |_|_|\_\
7
7
  # |_| |___/
8
- # -----------------------------------------------------------------------------
8
+ # -------------------------------------------------------------------------------------------------
9
9
  SHELL := /bin/sh
10
10
  GIT ?= git
11
11
  CP := cp
@@ -16,8 +16,7 @@ EMAILS = set-of-emails
16
16
 
17
17
 
18
18
  .DEFAULT_GOAL = git-status
19
-
20
- # -----------------------------------------------------------------------------
19
+ # -------------------------------------------------------------------------------------------------
21
20
  .PHONY: clean
22
21
 
23
22
  git-status: