sisimai 5.1.0-java → 5.2.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/rake-test.yml +1 -1
- data/ChangeLog.md +102 -0
- data/Makefile +4 -2
- data/README-JA.md +23 -16
- data/README.md +22 -15
- data/lib/sisimai/arf.rb +121 -210
- data/lib/sisimai/fact.rb +208 -158
- data/lib/sisimai/lda.rb +98 -0
- data/lib/sisimai/lhost/activehunter.rb +1 -1
- data/lib/sisimai/lhost/amazonses.rb +185 -301
- data/lib/sisimai/lhost/apachejames.rb +48 -51
- data/lib/sisimai/lhost/biglobe.rb +1 -2
- data/lib/sisimai/lhost/courier.rb +10 -8
- data/lib/sisimai/lhost/domino.rb +25 -25
- data/lib/sisimai/lhost/dragonfly.rb +3 -4
- data/lib/sisimai/lhost/einsundeins.rb +3 -4
- data/lib/sisimai/lhost/exchange2003.rb +6 -8
- data/lib/sisimai/lhost/exchange2007.rb +111 -101
- data/lib/sisimai/lhost/exim.rb +232 -242
- data/lib/sisimai/lhost/ezweb.rb +43 -51
- data/lib/sisimai/lhost/fml.rb +2 -3
- data/lib/sisimai/lhost/gmail.rb +32 -28
- data/lib/sisimai/lhost/gmx.rb +4 -16
- data/lib/sisimai/lhost/googlegroups.rb +9 -8
- data/lib/sisimai/lhost/googleworkspace.rb +94 -0
- data/lib/sisimai/lhost/imailserver.rb +7 -16
- data/lib/sisimai/lhost/interscanmss.rb +1 -1
- data/lib/sisimai/lhost/kddi.rb +3 -4
- data/lib/sisimai/lhost/mailfoundry.rb +2 -5
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +1 -2
- data/lib/sisimai/lhost/messagingserver.rb +14 -13
- data/lib/sisimai/lhost/mfilter.rb +4 -3
- data/lib/sisimai/lhost/notes.rb +2 -4
- data/lib/sisimai/lhost/opensmtpd.rb +2 -2
- data/lib/sisimai/lhost/postfix.rb +25 -27
- data/lib/sisimai/lhost/qmail.rb +130 -106
- data/lib/sisimai/lhost/sendmail.rb +19 -18
- data/lib/sisimai/lhost/v5sendmail.rb +88 -60
- data/lib/sisimai/lhost/verizon.rb +2 -2
- data/lib/sisimai/lhost/x1.rb +1 -1
- data/lib/sisimai/lhost/x2.rb +1 -2
- data/lib/sisimai/lhost/x3.rb +2 -2
- data/lib/sisimai/lhost/x6.rb +1 -1
- data/lib/sisimai/lhost/zoho.rb +2 -2
- data/lib/sisimai/lhost.rb +18 -21
- data/lib/sisimai/message.rb +93 -146
- data/lib/sisimai/order.rb +21 -77
- data/lib/sisimai/reason/authfailure.rb +1 -4
- data/lib/sisimai/reason/badreputation.rb +2 -2
- data/lib/sisimai/reason/blocked.rb +7 -10
- data/lib/sisimai/reason/contenterror.rb +7 -1
- data/lib/sisimai/reason/exceedlimit.rb +1 -4
- data/lib/sisimai/reason/failedstarttls.rb +42 -0
- data/lib/sisimai/reason/filtered.rb +5 -4
- data/lib/sisimai/reason/hasmoved.rb +1 -2
- data/lib/sisimai/reason/hostunknown.rb +3 -3
- data/lib/sisimai/reason/mailboxfull.rb +2 -4
- data/lib/sisimai/reason/mailererror.rb +1 -2
- data/lib/sisimai/reason/mesgtoobig.rb +2 -4
- data/lib/sisimai/reason/norelaying.rb +2 -3
- data/lib/sisimai/reason/notaccept.rb +2 -3
- data/lib/sisimai/reason/notcompliantrfc.rb +10 -4
- data/lib/sisimai/reason/rejected.rb +1 -1
- data/lib/sisimai/reason/requireptr.rb +2 -2
- data/lib/sisimai/reason/securityerror.rb +1 -3
- data/lib/sisimai/reason/spamdetected.rb +6 -8
- data/lib/sisimai/reason/speeding.rb +1 -2
- data/lib/sisimai/reason/suppressed.rb +36 -0
- data/lib/sisimai/reason/suspend.rb +1 -3
- data/lib/sisimai/reason/systemerror.rb +5 -0
- data/lib/sisimai/reason/toomanyconn.rb +1 -2
- data/lib/sisimai/reason/userunknown.rb +1 -1
- data/lib/sisimai/reason/virusdetected.rb +5 -6
- data/lib/sisimai/reason.rb +77 -73
- data/lib/sisimai/rfc1123.rb +152 -0
- data/lib/sisimai/rfc1894.rb +102 -62
- data/lib/sisimai/rfc2045.rb +2 -1
- data/lib/sisimai/rfc3464/thirdparty.rb +102 -0
- data/lib/sisimai/rfc3464.rb +222 -343
- data/lib/sisimai/rfc3834.rb +1 -1
- data/lib/sisimai/rfc5322.rb +7 -17
- data/lib/sisimai/rfc791.rb +69 -0
- data/lib/sisimai/rhost/aol.rb +36 -0
- data/lib/sisimai/rhost/apple.rb +5 -2
- data/lib/sisimai/rhost/cox.rb +3 -2
- data/lib/sisimai/rhost/facebook.rb +100 -0
- data/lib/sisimai/rhost/franceptt.rb +3 -2
- data/lib/sisimai/rhost/godaddy.rb +3 -2
- data/lib/sisimai/rhost/google.rb +19 -17
- data/lib/sisimai/rhost/gsuite.rb +42 -0
- data/lib/sisimai/rhost/iua.rb +3 -3
- data/lib/sisimai/rhost/kddi.rb +3 -2
- data/lib/sisimai/rhost/messagelabs.rb +37 -0
- data/lib/sisimai/rhost/microsoft.rb +56 -49
- data/lib/sisimai/rhost/mimecast.rb +29 -27
- data/lib/sisimai/rhost/nttdocomo.rb +4 -3
- data/lib/sisimai/rhost/outlook.rb +36 -0
- data/lib/sisimai/rhost/spectrum.rb +3 -2
- data/lib/sisimai/rhost/tencent.rb +3 -2
- data/lib/sisimai/rhost/yahooinc.rb +4 -3
- data/lib/sisimai/rhost.rb +69 -39
- data/lib/sisimai/smtp/command.rb +31 -21
- data/lib/sisimai/smtp/failure.rb +103 -0
- data/lib/sisimai/smtp/reply.rb +29 -25
- data/lib/sisimai/smtp/status.rb +36 -19
- data/lib/sisimai/smtp/transcript.rb +15 -15
- data/lib/sisimai/string.rb +0 -46
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/maildir/bsd/lhost-postfix-30.eml +81 -81
- data/set-of-emails/maildir/bsd/{lhost-aol-03.eml → rhost-aol-03.eml} +1264 -1264
- data/set-of-emails/maildir/bsd/{lhost-aol-04.eml → rhost-aol-04.eml} +1260 -1260
- data/set-of-emails/maildir/bsd/{lhost-aol-05.eml → rhost-aol-05.eml} +105 -105
- data/set-of-emails/maildir/bsd/{lhost-aol-06.eml → rhost-aol-06.eml} +105 -105
- data/set-of-emails/maildir/bsd/rhost-gsuite-01.eml +189 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-02.eml +180 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-03.eml +251 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-04.eml +211 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-05.eml +226 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-06.eml +257 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-07.eml +289 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-08.eml +231 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-09.eml +231 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-10.eml +254 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-11.eml +228 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-12.eml +271 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-13.eml +261 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-14.eml +273 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/{lhost-messagelabs-01.eml → rhost-messagelabs-01.eml} +93 -93
- data/set-of-emails/maildir/bsd/rhost-outlook-01.eml +72 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-02.eml +72 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-03.eml +72 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-04.eml +79 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-06.eml +75 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-07.eml +70 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-08.eml +70 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-09.eml +56 -0
- data/set-of-emails/maildir/tmp/arf-22.eml +49 -0
- data/set-of-emails/maildir/tmp/arf-23.eml +49 -0
- data/set-of-emails/maildir/tmp/arf-24.eml +50 -0
- data/set-of-emails/maildir/tmp/lhost-exim-07.eml +28 -0
- metadata +73 -56
- data/lib/sisimai/lhost/amavis.rb +0 -163
- data/lib/sisimai/lhost/amazonworkmail.rb +0 -127
- data/lib/sisimai/lhost/aol.rb +0 -125
- data/lib/sisimai/lhost/barracuda.rb +0 -92
- data/lib/sisimai/lhost/bigfoot.rb +0 -125
- data/lib/sisimai/lhost/facebook.rb +0 -188
- data/lib/sisimai/lhost/gsuite.rb +0 -194
- data/lib/sisimai/lhost/mailru.rb +0 -214
- data/lib/sisimai/lhost/mcafee.rb +0 -109
- data/lib/sisimai/lhost/messagelabs.rb +0 -120
- data/lib/sisimai/lhost/mxlogic.rb +0 -198
- data/lib/sisimai/lhost/office365.rb +0 -252
- data/lib/sisimai/lhost/outlook.rb +0 -129
- data/lib/sisimai/lhost/powermta.rb +0 -118
- data/lib/sisimai/lhost/receivingses.rb +0 -126
- data/lib/sisimai/lhost/sendgrid.rb +0 -150
- data/lib/sisimai/lhost/surfcontrol.rb +0 -105
- data/lib/sisimai/lhost/x4.rb +0 -269
- data/lib/sisimai/lhost/x5.rb +0 -112
- data/lib/sisimai/lhost/yahoo.rb +0 -102
- data/lib/sisimai/lhost/yandex.rb +0 -118
- data/lib/sisimai/mda.rb +0 -121
- data/lib/sisimai/smtp/error.rb +0 -119
- /data/set-of-emails/maildir/bsd/{lhost-googlegroups-15.eml → lhost-googleworkspace-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-x4-08.eml → lhost-x2-06.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-01.eml → rfc3464-51.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-03.eml → rfc3464-52.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-04.eml → rfc3464-53.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-05.eml → rfc3464-54.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-06.eml → rfc3464-55.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-07.eml → rfc3464-56.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-08.eml → rfc3464-57.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-09.eml → rfc3464-58.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-10.eml → rfc3464-59.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-11.eml → rfc3464-60.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-12.eml → rfc3464-61.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-13.eml → rfc3464-62.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-14.eml → rfc3464-63.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-15.eml → rfc3464-64.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-02.eml → rfc3464-65.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-aol-01.eml → rhost-aol-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-aol-02.eml → rhost-aol-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-facebook-03.eml → rhost-facebook-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-facebook-04.eml → rhost-facebook-04.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-messagelabs-02.eml → rhost-messagelabs-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-messagelabs-03.eml → rhost-messagelabs-03.eml} +0 -0
- /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-37.eml +0 -0
- /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-38.eml +0 -0
- /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-39.eml +0 -0
data/lib/sisimai/fact.rb
CHANGED
@@ -2,26 +2,32 @@ module Sisimai
|
|
2
2
|
# Sisimai::Fact generate the list of decoded bounce data
|
3
3
|
class Fact
|
4
4
|
require 'sisimai/message'
|
5
|
+
require 'sisimai/rfc791'
|
6
|
+
require 'sisimai/rfc1123'
|
5
7
|
require 'sisimai/rfc1894'
|
6
8
|
require 'sisimai/rfc5322'
|
7
9
|
require 'sisimai/reason'
|
8
10
|
require 'sisimai/address'
|
9
11
|
require 'sisimai/datetime'
|
10
12
|
require 'sisimai/time'
|
11
|
-
require 'sisimai/smtp/
|
13
|
+
require 'sisimai/smtp/failure'
|
12
14
|
require 'sisimai/smtp/command'
|
13
15
|
require 'sisimai/string'
|
14
16
|
require 'sisimai/rhost'
|
17
|
+
require 'sisimai/lda'
|
15
18
|
|
16
19
|
@@rwaccessors = [
|
17
20
|
:action, # [String] The value of Action: header
|
18
21
|
:addresser, # [Sisimai::Address] From address
|
19
22
|
:alias, # [String] Alias of the recipient address
|
20
23
|
:catch, # [?] Results generated by hook method
|
24
|
+
:command, # [String] The last SMTP command
|
25
|
+
:decodedby, # [String] MTA module name since v5.2.0
|
21
26
|
:deliverystatus, # [String] Delivery Status(DSN)
|
22
|
-
:destination, # [String] The domain part of the "
|
27
|
+
:destination, # [String] The domain part of the "recipient"
|
23
28
|
:diagnosticcode, # [String] Diagnostic-Code: Header
|
24
29
|
:diagnostictype, # [String] The 1st part of Diagnostic-Code: Header
|
30
|
+
:feedbackid, # [String] The value of Feedback-ID: header of the original message
|
25
31
|
:feedbacktype, # [String] Feedback Type
|
26
32
|
:hardbounce, # [Boolean] true = Hard bounce, false = is not a hard bounce
|
27
33
|
:lhost, # [String] local host name/Local MTA
|
@@ -33,8 +39,6 @@ module Sisimai
|
|
33
39
|
:replycode, # [String] SMTP Reply Code
|
34
40
|
:rhost, # [String] Remote host name/Remote MTA
|
35
41
|
:senderdomain, # [String] The domain part of the "addresser"
|
36
|
-
:smtpagent, # [String] Module(Engine) name
|
37
|
-
:smtpcommand, # [String] The last SMTP command
|
38
42
|
:subject, # [String] UTF-8 Subject text
|
39
43
|
:timestamp, # [Sisimai::Time] Date: header in the original message
|
40
44
|
:timezoneoffset, # [Integer] Time zone offset(seconds)
|
@@ -43,7 +47,7 @@ module Sisimai
|
|
43
47
|
attr_accessor(*@@rwaccessors)
|
44
48
|
|
45
49
|
RetryIndex = Sisimai::Reason.retry
|
46
|
-
RFC822Head = Sisimai::RFC5322.
|
50
|
+
RFC822Head = Sisimai::RFC5322.HEADERTABLE
|
47
51
|
ActionList = { delayed: 1, delivered: 1, expanded: 1, failed: 1, relayed: 1 };
|
48
52
|
|
49
53
|
if RUBY_PLATFORM.start_with?('java')
|
@@ -67,10 +71,13 @@ module Sisimai
|
|
67
71
|
@addresser = argvs['addresser']
|
68
72
|
@action = argvs['action']
|
69
73
|
@catch = argvs['catch']
|
74
|
+
@command = argvs['command']
|
75
|
+
@decodedby = argvs['decodedby']
|
70
76
|
@diagnosticcode = argvs['diagnosticcode']
|
71
77
|
@diagnostictype = argvs['diagnostictype']
|
72
78
|
@deliverystatus = argvs['deliverystatus']
|
73
79
|
@destination = argvs['recipient'].host
|
80
|
+
@feedbackid = argvs["feedbackid"]
|
74
81
|
@feedbacktype = argvs['feedbacktype']
|
75
82
|
@hardbounce = argvs['hardbounce']
|
76
83
|
@lhost = argvs['lhost']
|
@@ -82,8 +89,6 @@ module Sisimai
|
|
82
89
|
@replycode = argvs['replycode']
|
83
90
|
@rhost = argvs['rhost']
|
84
91
|
@senderdomain = argvs['addresser'].host
|
85
|
-
@smtpagent = argvs['smtpagent']
|
86
|
-
@smtpcommand = argvs['smtpcommand']
|
87
92
|
@subject = argvs['subject']
|
88
93
|
@token = argvs['token']
|
89
94
|
@timestamp = argvs['timestamp']
|
@@ -93,11 +98,9 @@ module Sisimai
|
|
93
98
|
# Constructor of Sisimai::Fact
|
94
99
|
# @param [Hash] argvs
|
95
100
|
# @options argvs [String] data Entire email message
|
96
|
-
# @options argvs [Boolean] delivered
|
97
|
-
# @options argvs [Boolean] vacation
|
98
|
-
# @options argvs [Proc] hook Proc object of callback method
|
99
|
-
# @options argvs [Array] load User defined MTA module list
|
100
|
-
# @options argvs [Array] order The order of MTA modules
|
101
|
+
# @options argvs [Boolean] delivered true if the result which has "delivered" reason is included
|
102
|
+
# @options argvs [Boolean] vacation true if the result which has "vacation" reason is included
|
103
|
+
# @options argvs [Proc] hook Proc object of the callback method
|
101
104
|
# @options argvs [String] origin Path to the original email file
|
102
105
|
# @return [Array] Array of Sisimai::Fact objects
|
103
106
|
def self.rise(**argvs)
|
@@ -105,11 +108,8 @@ module Sisimai
|
|
105
108
|
return nil unless argvs.is_a? Hash
|
106
109
|
|
107
110
|
email = argvs[:data]; return nil unless email
|
108
|
-
|
109
|
-
order = argvs[:order] || nil
|
110
|
-
args1 = { data: email, hook: argvs[:hook], load: loads, order: order }
|
111
|
+
args1 = { data: email, hook: argvs[:hook] }
|
111
112
|
mesg1 = Sisimai::Message.rise(**args1)
|
112
|
-
|
113
113
|
return nil unless mesg1
|
114
114
|
return nil unless mesg1['ds']
|
115
115
|
return nil unless mesg1['rfc822']
|
@@ -120,55 +120,48 @@ module Sisimai
|
|
120
120
|
|
121
121
|
while e = deliveries.shift do
|
122
122
|
# Create parameters for each Sisimai::Fact object
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
123
|
+
next if e['recipient'].size < 5
|
124
|
+
next if ! argvs[:vacation] && e['reason'] == 'vacation'
|
125
|
+
next if ! argvs[:delivered] && e['status'].start_with?('2.')
|
126
|
+
|
127
|
+
thing = {} # To be passed to each accessor of Sisimai::Fact
|
128
|
+
piece = {
|
129
|
+
"action" => e["action"],
|
130
|
+
"alias" => e["alias"],
|
131
|
+
"catch" => mesg1["catch"] || nil,
|
132
|
+
"command" => e["command"],
|
133
|
+
"deliverystatus" => e["status"],
|
134
|
+
"diagnosticcode" => e["diagnosis"],
|
135
|
+
"diagnostictype" => e["spec"],
|
136
|
+
"feedbacktype" => e["feedbacktype"],
|
137
|
+
"hardbounce" => false,
|
138
|
+
"lhost" => e["lhost"],
|
139
|
+
"origin" => argvs[:origin],
|
140
|
+
"reason" => e["reason"],
|
141
|
+
"recipient" => e["recipient"],
|
142
|
+
"replycode" => e["replycode"],
|
143
|
+
"rhost" => e["rhost"],
|
144
|
+
"decodedby" => e["agent"],
|
141
145
|
}
|
142
|
-
unless argvs[:delivered]
|
143
|
-
# Skip if the value of "deliverystatus" begins with "2." such as 2.1.5
|
144
|
-
next if p['deliverystatus'].start_with?('2.')
|
145
|
-
end
|
146
|
-
|
147
|
-
unless argvs[:vacation]
|
148
|
-
# Skip if the value of "reason" is "vacation"
|
149
|
-
next if p['reason'] == 'vacation'
|
150
|
-
end
|
151
146
|
|
152
|
-
# EMAILADDRESS: Detect email address from message/rfc822 part
|
147
|
+
# EMAILADDRESS: Detect an email address from message/rfc822 part
|
153
148
|
RFC822Head[:addresser].each do |f|
|
154
149
|
# Check each header in message/rfc822 part
|
155
|
-
|
156
|
-
next
|
157
|
-
next if rfc822data[g].empty?
|
150
|
+
next unless rfc822data[f]
|
151
|
+
next if rfc822data[f].empty?
|
158
152
|
|
159
|
-
j = Sisimai::Address.find(rfc822data[
|
160
|
-
|
153
|
+
j = Sisimai::Address.find(rfc822data[f]) || next
|
154
|
+
piece['addresser'] = j.shift
|
161
155
|
break
|
162
156
|
end
|
163
157
|
|
164
|
-
unless
|
158
|
+
unless piece['addresser']
|
165
159
|
# Fallback: Get the sender address from the header of the bounced email if the address is
|
166
160
|
# not set at loop above.
|
167
161
|
j = Sisimai::Address.find(mesg1['header']['to']) || []
|
168
|
-
|
162
|
+
piece['addresser'] = j.shift
|
169
163
|
end
|
170
|
-
next unless
|
171
|
-
next unless p['recipient']
|
164
|
+
next unless piece['addresser']
|
172
165
|
|
173
166
|
# TIMESTAMP: Convert from a time stamp or a date string to a machine time.
|
174
167
|
datestring = nil
|
@@ -184,54 +177,91 @@ module Sisimai
|
|
184
177
|
|
185
178
|
# Set "date" getting from the value of "Date" in the bounce message
|
186
179
|
datevalues << mesg1['header']['date'] if datevalues.size < 2
|
187
|
-
|
188
180
|
while v = datevalues.shift do
|
189
181
|
# Parse each date value in the array
|
190
|
-
datestring = Sisimai::DateTime.parse(v)
|
191
|
-
break if datestring
|
192
|
-
end
|
182
|
+
datestring = Sisimai::DateTime.parse(v) || next
|
193
183
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
184
|
+
if cv = datestring.match(/\A(.+)[ ]+([-+]\d{4})\z/)
|
185
|
+
# Get the value of timezone offset from datestring: Wed, 26 Feb 2014 06:05:48 -0500
|
186
|
+
datestring = cv[1]
|
187
|
+
zoneoffset = Sisimai::DateTime.tz2second(cv[2])
|
188
|
+
piece['timezoneoffset'] = cv[2]
|
189
|
+
end
|
190
|
+
break if datestring
|
199
191
|
end
|
200
192
|
|
201
193
|
begin
|
202
194
|
# Convert from the date string to an object then calculate time zone offset.
|
203
195
|
t = TimeModule.strptime(datestring, '%a, %d %b %Y %T')
|
204
|
-
|
196
|
+
piece['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
|
205
197
|
rescue
|
206
198
|
warn ' ***warning: Failed to strptime ' << datestring.to_s
|
207
199
|
end
|
208
|
-
next unless
|
200
|
+
next unless piece['timestamp']
|
209
201
|
|
210
202
|
# OTHER_TEXT_HEADERS:
|
211
|
-
|
212
|
-
|
213
|
-
#
|
214
|
-
|
215
|
-
|
216
|
-
|
203
|
+
recv = mesg1["header"]["received"] || []
|
204
|
+
if piece["rhost"].empty?
|
205
|
+
# Try to pick a remote hostname from Received: headers of the bounce message
|
206
|
+
ir = Sisimai::RFC1123.find(e["diagnosis"])
|
207
|
+
piece["rhost"] = ir if Sisimai::RFC1123.is_internethost(ir)
|
208
|
+
|
209
|
+
if piece["rhost"].empty?
|
210
|
+
# The remote hostname in the error message did not exist or is not a valid
|
211
|
+
# internet hostname
|
212
|
+
recv.reverse.each do |re|
|
213
|
+
# Check the Received: headers backwards and get a remote hostname
|
214
|
+
break if piece["rhost"].size > 0
|
215
|
+
cv = Sisimai::RFC5322.received(re)[0]
|
216
|
+
next unless Sisimai::RFC1123.is_internethost(cv)
|
217
|
+
piece['rhost'] = cv
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
piece["lhost"] = "" if piece["rhost"] == piece["lhost"]
|
222
|
+
|
223
|
+
if piece["lhost"].empty?
|
224
|
+
# Try to pick a local hostname from Received: headers of the bounce message
|
225
|
+
recv.each do |le|
|
226
|
+
# Check the Received: headers backwards and get a local hostname
|
227
|
+
cv = Sisimai::RFC5322.received(le)[0]
|
228
|
+
next unless Sisimai::RFC1123.is_internethost(cv)
|
229
|
+
piece['lhost'] = cv
|
230
|
+
break
|
231
|
+
end
|
217
232
|
end
|
218
233
|
|
219
234
|
# Remove square brackets and curly brackets from the host variable
|
220
235
|
%w[rhost lhost].each do |v|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
236
|
+
next if piece[v].empty?
|
237
|
+
|
238
|
+
if piece[v].include?('@')
|
239
|
+
# Use the domain part as a remote/local host when the value is an email address
|
240
|
+
piece[v] = piece[v].split('@')[-1]
|
241
|
+
end
|
242
|
+
piece[v].delete!('[]()') # Remove square brackets and curly brackets from the host variable
|
243
|
+
piece[v].sub!(/\A.+=/, '') # Remove string before "="
|
244
|
+
piece[v].sub!("\r", '') # Remove CR at the end of the value
|
245
|
+
|
246
|
+
if piece[v].include?(' ')
|
247
|
+
# Check space character in each value and get the first hostname
|
248
|
+
ee = piece[v].split(' ')
|
249
|
+
ee.each do |w|
|
250
|
+
# get a hostname from the string like "127.0.0.1 x109-20.example.com 192.0.2.20"
|
251
|
+
# or "mx.sp.example.jp 192.0.2.135"
|
252
|
+
next if Sisimai::RFC791.is_ipv4address(w)
|
253
|
+
piece[v] = w
|
254
|
+
break
|
255
|
+
end
|
256
|
+
end
|
257
|
+
piece[v] = ee[0] if piece[v].include?(' ')
|
258
|
+
piece[v].chomp!('.') if piece[v].end_with?('.') # Remove "." at the end of the value
|
229
259
|
end
|
230
260
|
|
231
261
|
# Subject: header of the original message
|
232
|
-
|
233
|
-
|
234
|
-
|
262
|
+
piece['subject'] = rfc822data['subject'] || ''
|
263
|
+
piece['subject'].scrub!('?')
|
264
|
+
piece['subject'].chomp!("\r") if piece['subject'].end_with?("\r")
|
235
265
|
|
236
266
|
# The value of "List-Id" header
|
237
267
|
if Sisimai::String.aligned(rfc822data['list-id'], ['<', '.', '>'])
|
@@ -239,10 +269,10 @@ module Sisimai
|
|
239
269
|
# Get the value of List-Id header: "List name <list-id@example.org>"
|
240
270
|
p0 = rfc822data['list-id'].index('<') + 1
|
241
271
|
p1 = rfc822data['list-id'].index('>')
|
242
|
-
|
272
|
+
piece['listid'] = rfc822data['list-id'][p0, p1 - p0]
|
243
273
|
else
|
244
274
|
# Invalid value of the List-Id: field
|
245
|
-
|
275
|
+
piece['listid'] = ''
|
246
276
|
end
|
247
277
|
|
248
278
|
# The value of "Message-Id" header
|
@@ -251,26 +281,26 @@ module Sisimai
|
|
251
281
|
# Leave only string inside of angle brackets(<>)
|
252
282
|
p0 = rfc822data['message-id'].index('<') + 1
|
253
283
|
p1 = rfc822data['message-id'].index('>')
|
254
|
-
|
284
|
+
piece['messageid'] = rfc822data['message-id'][p0, p1 - p0]
|
255
285
|
else
|
256
286
|
# Invalid value of the Message-Id: field
|
257
|
-
|
287
|
+
piece['messageid'] = ''
|
258
288
|
end
|
259
289
|
|
260
290
|
# CHECK_DELIVERY_STATUS_VALUE: Cleanup the value of "Diagnostic-Code:" header
|
261
|
-
if
|
291
|
+
if piece['diagnosticcode'].to_s.size > 0
|
262
292
|
# Get an SMTP Reply Code and an SMTP Enhanced Status Code
|
263
|
-
|
293
|
+
piece['diagnosticcode'].chop if piece['diagnosticcode'][-1, 1] == "\r"
|
264
294
|
|
265
|
-
cs = Sisimai::SMTP::Status.find(
|
266
|
-
cr = Sisimai::SMTP::Reply.find(
|
267
|
-
|
295
|
+
cs = Sisimai::SMTP::Status.find(piece['diagnosticcode'])
|
296
|
+
cr = Sisimai::SMTP::Reply.find(piece['diagnosticcode'], cs)
|
297
|
+
piece['deliverystatus'] = Sisimai::SMTP::Status.prefer(piece['deliverystatus'], cs, cr)
|
268
298
|
|
269
299
|
if cr.size == 3
|
270
300
|
# There is an SMTP reply code in the error message
|
271
|
-
|
301
|
+
piece['replycode'] = cr if piece['replycode'].empty?
|
272
302
|
|
273
|
-
if
|
303
|
+
if piece['diagnosticcode'].include?(cr + '-')
|
274
304
|
# 550-5.7.1 [192.0.2.222] Our system has detected that this message is
|
275
305
|
# 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,
|
276
306
|
# 550-5.7.1 this message has been blocked. Please visit
|
@@ -286,80 +316,84 @@ module Sisimai
|
|
286
316
|
['-', " "].each do |q|
|
287
317
|
# Remove strings: "550-5.7.1", and "550 5.7.1" from the error message
|
288
318
|
cx = sprintf("%s%s%s", cr, q, cs)
|
289
|
-
p0 =
|
319
|
+
p0 = piece['diagnosticcode'].index(cx)
|
290
320
|
while p0
|
291
321
|
# Remove strings like "550-5.7.1"
|
292
|
-
|
293
|
-
p0 =
|
322
|
+
piece['diagnosticcode'][p0, cx.size] = ''
|
323
|
+
p0 = piece['diagnosticcode'].index(cx)
|
294
324
|
end
|
295
325
|
|
296
326
|
# Remove "553-" and "553 " (SMTP reply code only) from the error message
|
297
327
|
cx = sprintf("%s%s", cr, q)
|
298
|
-
p0 =
|
328
|
+
p0 = piece['diagnosticcode'].index(cx)
|
299
329
|
while p0
|
300
330
|
# Remove strings like "553-"
|
301
|
-
|
302
|
-
p0 =
|
331
|
+
piece['diagnosticcode'][p0, cx.size] = ''
|
332
|
+
p0 = piece['diagnosticcode'].index(cx)
|
303
333
|
end
|
304
334
|
end
|
305
335
|
|
306
|
-
if
|
336
|
+
if piece['diagnosticcode'].index(cr).to_i > 1
|
307
337
|
# Add "550 5.1.1" into the head of the error message when the error message does not
|
308
338
|
# begin with "550"
|
309
|
-
|
339
|
+
piece['diagnosticcode'] = sprintf("%s %s %s", cr, cs, piece['diagnosticcode'])
|
310
340
|
end
|
311
341
|
end
|
312
342
|
end
|
313
343
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
344
|
+
dc = piece['diagnosticcode'].downcase
|
345
|
+
p1 = dc.index('<html>')
|
346
|
+
p2 = dc.index('</html>')
|
347
|
+
piece['diagnosticcode'][p1, p2 + 7 - p1] = '' if p1 && p2
|
348
|
+
piece['diagnosticcode'] = Sisimai::String.sweep(piece['diagnosticcode'])
|
318
349
|
end
|
319
350
|
|
320
|
-
if Sisimai::String.is_8bit(
|
351
|
+
if Sisimai::String.is_8bit(piece['diagnosticcode'])
|
321
352
|
# To avoid incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError
|
322
|
-
|
353
|
+
piece['diagnosticcode'] = piece['diagnosticcode'].force_encoding('UTF-8').scrub('?')
|
323
354
|
end
|
324
355
|
|
325
|
-
|
326
|
-
|
327
|
-
|
356
|
+
piece["diagnostictype"] = "X-UNIX" if piece["reason"] == "mailererror"
|
357
|
+
if piece["diagnostictype"].empty?
|
358
|
+
piece["diagnostictype"] = "SMTP" unless %w[feedback vacation].include?(piece["reason"])
|
359
|
+
end
|
328
360
|
|
329
361
|
# Check the value of SMTP command
|
330
|
-
|
362
|
+
piece['command'] = '' unless Sisimai::SMTP::Command.test(piece['command'])
|
331
363
|
|
332
364
|
# Create parameters for the constructor
|
333
|
-
as = Sisimai::Address.new(
|
334
|
-
ar = Sisimai::Address.new(address:
|
365
|
+
as = Sisimai::Address.new(piece['addresser']) || next; next if as.void
|
366
|
+
ar = Sisimai::Address.new(address: piece['recipient']) || next; next if ar.void
|
335
367
|
ea = %w[
|
336
|
-
action deliverystatus diagnosticcode diagnostictype feedbacktype lhost
|
337
|
-
origin reason replycode rhost
|
368
|
+
action command decodedby deliverystatus diagnosticcode diagnostictype feedbacktype lhost
|
369
|
+
listid messageid origin reason replycode rhost subject
|
338
370
|
]
|
339
371
|
|
340
|
-
|
372
|
+
thing = {
|
341
373
|
'addresser' => as,
|
342
374
|
'recipient' => ar,
|
343
375
|
'senderdomain' => as.host,
|
344
376
|
'destination' => ar.host,
|
345
|
-
'alias' =>
|
346
|
-
'token' => Sisimai::String.token(as.address, ar.address,
|
377
|
+
'alias' => piece['alias'] || ar.alias,
|
378
|
+
'token' => Sisimai::String.token(as.address, ar.address, piece['timestamp']),
|
347
379
|
}
|
380
|
+
ea.each { |q| thing[q] = piece[q] if thing[q].nil? || thing[q].empty? }
|
348
381
|
|
349
382
|
# Other accessors
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
383
|
+
thing['catch'] = piece['catch'] || nil
|
384
|
+
thing["feedbackid"] = ""
|
385
|
+
thing['hardbounce'] = piece['hardbounce']
|
386
|
+
thing['replycode'] = Sisimai::SMTP::Reply.find(piece['diagnosticcode']) if thing['replycode'].empty?
|
387
|
+
thing['timestamp'] = TimeModule.parse(::Time.at(piece['timestamp']).to_s)
|
388
|
+
thing['timezoneoffset'] = piece['timezoneoffset'] || '+0000'
|
389
|
+
ea.each { |q| thing[q] = piece[q] if thing[q].empty? }
|
356
390
|
|
357
391
|
# ALIAS
|
358
392
|
while true do
|
359
393
|
# 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
|
361
|
-
break if
|
362
|
-
break if
|
394
|
+
# when the recipient address is same with the value of thing['alias'].
|
395
|
+
break if thing['alias'].empty?
|
396
|
+
break if thing['recipient'].address != thing['alias']
|
363
397
|
break unless rfc822data.has_key?('received')
|
364
398
|
break if rfc822data['received'].empty?
|
365
399
|
|
@@ -371,68 +405,78 @@ module Sisimai
|
|
371
405
|
next if af.empty?
|
372
406
|
next if af[5].empty?
|
373
407
|
next unless Sisimai::Address.is_emailaddress(af[5])
|
374
|
-
next if
|
408
|
+
next if thing['recipient'].address == af[5]
|
375
409
|
|
376
|
-
|
410
|
+
thing['alias'] = af[5]
|
377
411
|
break
|
378
412
|
end
|
379
413
|
break
|
380
414
|
end
|
381
|
-
|
415
|
+
thing['alias'] = '' if thing['alias'] == thing['recipient'].address
|
382
416
|
|
383
417
|
# REASON: Decide the reason of email bounce
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
418
|
+
while true
|
419
|
+
if thing["reason"].empty? || RetryIndex[thing["reason"]]
|
420
|
+
# The value of "reason" is empty or is needed to check with other values again
|
421
|
+
re = thing["reason"].empty? ? "undefined" : thing["reason"]
|
422
|
+
cr = Sisimai::LDA.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
|
423
|
+
cr = Sisimai::Rhost.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
|
424
|
+
cr = Sisimai::Reason.find(thing); if Sisimai::Reason.is_explicit(cr) then thing["reason"] = cr; break; end
|
425
|
+
thing["reason"] = thing["diagnosticcode"].size > 0 ? "onhold" : re
|
426
|
+
break
|
427
|
+
end
|
428
|
+
break
|
389
429
|
end
|
390
430
|
|
391
431
|
# HARDBOUNCE: Set the value of "hardbounce", default value of "bouncebounce" is false
|
392
|
-
if
|
393
|
-
#
|
394
|
-
|
432
|
+
if thing['reason'] == 'delivered' || thing['reason'] == 'feedback' || thing['reason'] == 'vacation'
|
433
|
+
# Delete the value of ReplyCode when the Reason is "feedback" or "vacation"
|
434
|
+
thing['replycode'] = '' unless thing['reason'] == 'delivered'
|
395
435
|
else
|
396
|
-
|
436
|
+
# The reason is not "delivered", or "feedback", or "vacation"
|
437
|
+
smtperrors = piece['deliverystatus'] + ' ' << piece['diagnosticcode']
|
397
438
|
smtperrors = '' if smtperrors.size < 4
|
398
|
-
|
399
|
-
o['hardbounce'] = true if softorhard == 'hard'
|
439
|
+
thing['hardbounce'] = Sisimai::SMTP::Failure.is_hardbounce(thing['reason'], smtperrors)
|
400
440
|
end
|
401
441
|
|
402
442
|
# DELIVERYSTATUS: Set a pseudo status code if the value of "deliverystatus" is empty
|
403
|
-
if
|
404
|
-
smtperrors =
|
443
|
+
if thing['deliverystatus'].empty?
|
444
|
+
smtperrors = piece['replycode'] + ' ' << piece['diagnosticcode']
|
405
445
|
smtperrors = '' if smtperrors.size < 4
|
406
|
-
|
407
|
-
|
408
|
-
|
446
|
+
permanent0 = Sisimai::SMTP::Failure.is_permanent(smtperrors)
|
447
|
+
temporary0 = Sisimai::SMTP::Failure.is_temporary(smtperrors)
|
448
|
+
temporary1 = temporary0; temporary1 = false if !permanent0 && !temporary1
|
449
|
+
thing['deliverystatus'] = Sisimai::SMTP::Status.code(thing['reason'], temporary1) || ''
|
409
450
|
end
|
410
451
|
|
411
452
|
# REPLYCODE: Check both of the first digit of "deliverystatus" and "replycode"
|
412
|
-
cx = [
|
453
|
+
cx = [thing['deliverystatus'][0, 1], thing['replycode'][0, 1]]
|
413
454
|
if cx[0] != cx[1]
|
414
455
|
# The class of the "Status:" is defer with the first digit of the reply code
|
415
|
-
cx[1] = Sisimai::SMTP::Reply.find(
|
416
|
-
|
456
|
+
cx[1] = Sisimai::SMTP::Reply.find(piece['diagnosticcode'], cx[0])
|
457
|
+
thing['replycode'] = cx[1].start_with?(cx[0]) ? cx[1] : ''
|
417
458
|
end
|
418
459
|
|
419
|
-
unless ActionList.has_key?(
|
460
|
+
unless ActionList.has_key?(thing['action'])
|
420
461
|
# There is an action value which is not described at RFC1894
|
421
|
-
if ox = Sisimai::RFC1894.field('Action: ' <<
|
462
|
+
if ox = Sisimai::RFC1894.field('Action: ' << thing['action'])
|
422
463
|
# Rewrite the value of "Action:" field to the valid value
|
423
464
|
#
|
424
465
|
# The syntax for the action-field is:
|
425
466
|
# action-field = "Action" ":" action-value
|
426
467
|
# action-value = "failed" / "delayed" / "delivered" / "relayed" / "expanded"
|
427
|
-
|
468
|
+
thing['action'] = ox[2]
|
428
469
|
end
|
429
470
|
end
|
430
|
-
|
431
|
-
if
|
432
|
-
|
433
|
-
|
471
|
+
thing["action"] = "" if thing["action"].nil?
|
472
|
+
thing["action"] = "delivered" if thing["action"].empty? && thing["reason"] == "delivered"
|
473
|
+
thing["action"] = "delayed" if thing["action"].empty? && thing["reason"] == "expired"
|
474
|
+
thing["action"] = "failed" if thing["action"].empty? && cx[0] == "4" || cx[0] == "5"
|
475
|
+
|
476
|
+
# Feedback-ID: 1.us-west-2.QHuyeCQrGtIIMGKQfVdUhP9hCQR2LglVOrRamBc+Prk=:AmazonSES
|
477
|
+
thing["feedbackid"] = rfc822data["feedback-id"] || ""
|
434
478
|
|
435
|
-
listoffact << Sisimai::Fact.new(
|
479
|
+
listoffact << Sisimai::Fact.new(thing)
|
436
480
|
end
|
437
481
|
return listoffact
|
438
482
|
end
|
@@ -442,8 +486,8 @@ module Sisimai
|
|
442
486
|
def damn
|
443
487
|
data = {}
|
444
488
|
stringdata = %w[
|
445
|
-
action alias catch deliverystatus destination diagnosticcode diagnostictype
|
446
|
-
lhost listid messageid origin reason replycode rhost senderdomain
|
489
|
+
action alias catch command decodedby deliverystatus destination diagnosticcode diagnostictype
|
490
|
+
feedbackid feedbacktype lhost listid messageid origin reason replycode rhost senderdomain
|
447
491
|
subject timezoneoffset token
|
448
492
|
]
|
449
493
|
|
@@ -454,6 +498,10 @@ module Sisimai
|
|
454
498
|
v['addresser'] = self.addresser.address
|
455
499
|
v['recipient'] = self.recipient.address
|
456
500
|
v['timestamp'] = self.timestamp.to_time.to_i
|
501
|
+
|
502
|
+
# Backward compatibility until v5.2.0
|
503
|
+
v["smtpagent"] = self.decodedby
|
504
|
+
v["smtpcommand"] = self.command
|
457
505
|
data = v
|
458
506
|
rescue
|
459
507
|
warn ' ***warning: Failed to execute Sisimai::Fact.damn'
|
@@ -486,6 +534,8 @@ module Sisimai
|
|
486
534
|
return self.dump('json')
|
487
535
|
end
|
488
536
|
|
537
|
+
def smtpagent; warn " ***warning: Sisimai::Fact.smtpagent will be removed at v5.5.0"; return self.decodedby; end
|
538
|
+
def smtpcomand; warn " ***warning: Sisimai::Fact.smtpcommand will be removed at v5.5.0"; return self.command; end
|
489
539
|
end
|
490
540
|
end
|
491
541
|
|