sisimai 4.25.15 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +419 -388
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +140 -78
- data/README.md +290 -143
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +23 -18
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -313
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -47
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +12 -12
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +41 -20
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
data/lib/sisimai/lhost/ezweb.rb
CHANGED
@@ -1,41 +1,28 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::EZweb parses a bounce email which created by au EZweb.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::EZweb parses a bounce email which created by au EZweb. Methods in the module are
|
3
|
+
# called from only Sisimai::Message.
|
4
4
|
module EZweb
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/EZweb.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
11
|
-
MarkingsOf = {
|
12
|
-
message: %r{\A(?:
|
13
|
-
The[ ]user[(]s[)][ ]
|
14
|
-
|Your[ ]message[ ]
|
15
|
-
|Each[ ]of[ ]the[ ]following
|
16
|
-
|[<][^ ]+[@][^ ]+[>]\z
|
17
|
-
)
|
18
|
-
}x,
|
19
|
-
}.freeze
|
9
|
+
Boundaries = ['--------------------------------------------------', 'Content-Type: message/rfc822'].freeze
|
10
|
+
MarkingsOf = { message: ['The user(s) ', 'Your message ', 'Each of the following', '<'] }.freeze
|
20
11
|
ReFailures = {
|
21
|
-
# notaccept: [
|
22
|
-
'mailboxfull' => [
|
23
|
-
%r/The user[(]s[)] account is temporarily over quota/,
|
24
|
-
],
|
12
|
+
# notaccept: ['The following recipients did not receive this message:'],
|
13
|
+
'mailboxfull' => ['The user(s) account is temporarily over quota'],
|
25
14
|
'suspend' => [
|
26
15
|
# http://www.naruhodo-au.kddi.com/qa3429203.html
|
27
16
|
# The recipient may be unpaid user...?
|
28
|
-
|
29
|
-
|
17
|
+
'The user(s) account is disabled.',
|
18
|
+
'The user(s) account is temporarily limited.',
|
30
19
|
],
|
31
20
|
'expired' => [
|
32
21
|
# Your message was not delivered within 0 days and 1 hours.
|
33
22
|
# Remote host is not responding.
|
34
|
-
|
35
|
-
],
|
36
|
-
'onhold' => [
|
37
|
-
%r/Each of the following recipients was rejected by a remote mail server/,
|
23
|
+
'Your message was not delivered within ',
|
38
24
|
],
|
25
|
+
'onhold' => ['Each of the following recipients was rejected by a remote mail server'],
|
39
26
|
}.freeze
|
40
27
|
|
41
28
|
# Parse bounce messages from au EZweb
|
@@ -43,7 +30,7 @@ module Sisimai::Lhost
|
|
43
30
|
# @param [String] mbody Message body of a bounce email
|
44
31
|
# @return [Hash] Bounce data list and message/rfc822 part
|
45
32
|
# @return [Nil] it failed to parse or the arguments are missing
|
46
|
-
def
|
33
|
+
def inquire(mhead, mbody)
|
47
34
|
match = 0
|
48
35
|
match += 1 if mhead['from'].include?('Postmaster@ezweb.ne.jp')
|
49
36
|
match += 1 if mhead['from'].include?('Postmaster@au.com')
|
@@ -55,31 +42,21 @@ module Sisimai::Lhost
|
|
55
42
|
end
|
56
43
|
return nil if match < 2
|
57
44
|
|
58
|
-
require 'sisimai/rfc1894'
|
59
45
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
60
46
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
61
|
-
|
62
|
-
bodyslices =
|
47
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
48
|
+
bodyslices = emailparts[0].split("\n")
|
63
49
|
readcursor = 0 # (Integer) Points the current cursor position
|
64
50
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
65
|
-
|
51
|
+
rxmessages = []; ReFailures.each_value { |a| rxmessages << a }
|
66
52
|
v = nil
|
67
53
|
|
68
|
-
if mhead['content-type']
|
69
|
-
# Get the boundary string and set regular expression for matching with
|
70
|
-
# the boundary string.
|
71
|
-
b0 = Sisimai::MIME.boundary(mhead['content-type'], 1)
|
72
|
-
rxboundary = Regexp.new('\A' << Regexp.escape(b0) << '\z') unless b0.empty?
|
73
|
-
end
|
74
|
-
rxmessages = []
|
75
|
-
ReFailures.each_value { |a| rxmessages << a }
|
76
|
-
|
77
54
|
while e = bodyslices.shift do
|
78
|
-
# Read error messages and delivery status lines from the head of the email
|
79
|
-
#
|
55
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
56
|
+
# line of the beginning of the original message.
|
80
57
|
if readcursor == 0
|
81
58
|
# Beginning of the bounce message or delivery status part
|
82
|
-
readcursor |= Indicators[:deliverystatus] if
|
59
|
+
readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.include?(a) }
|
83
60
|
end
|
84
61
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
85
62
|
next if e.empty?
|
@@ -97,18 +74,17 @@ module Sisimai::Lhost
|
|
97
74
|
# <<< 550 <******@ezweb.ne.jp>: User unknown
|
98
75
|
v = dscontents[-1]
|
99
76
|
|
100
|
-
if
|
101
|
-
|
102
|
-
|
77
|
+
if Sisimai::String.aligned(e, ['<', '@', '>']) && (e.include?('Recipient: <') || e.start_with?('<'))
|
78
|
+
# Recipient: <******@ezweb.ne.jp> OR <***@ezweb.ne.jp>: 550 user unknown ...
|
79
|
+
p1 = e.index('<') || -1
|
80
|
+
p2 = e.index('>') || -1
|
103
81
|
|
104
82
|
if v['recipient']
|
105
83
|
# There are multiple recipient addresses in the message body.
|
106
84
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
107
85
|
v = dscontents[-1]
|
108
86
|
end
|
109
|
-
|
110
|
-
r = Sisimai::Address.s3s4(cv[1])
|
111
|
-
v['recipient'] = r
|
87
|
+
v['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
|
112
88
|
recipients += 1
|
113
89
|
|
114
90
|
elsif f = Sisimai::RFC1894.match(e)
|
@@ -120,12 +96,12 @@ module Sisimai::Lhost
|
|
120
96
|
else
|
121
97
|
# The line does not begin with a DSN field defined in RFC3464
|
122
98
|
next if Sisimai::String.is_8bit(e)
|
123
|
-
if
|
99
|
+
if e.include?('>>> ')
|
124
100
|
# >>> RCPT TO:<******@ezweb.ne.jp>
|
125
|
-
v['command'] =
|
101
|
+
v['command'] = Sisimai::SMTP::Command.find(e) || ''
|
126
102
|
else
|
127
103
|
# Check error message
|
128
|
-
if rxmessages.any? { |messages| messages.any? { |message| e
|
104
|
+
if rxmessages.any? { |messages| messages.any? { |message| e.include?(message) } }
|
129
105
|
# Check with regular expressions of each error
|
130
106
|
v['diagnosis'] ||= ''
|
131
107
|
v['diagnosis'] << ' ' << e
|
@@ -149,7 +125,7 @@ module Sisimai::Lhost
|
|
149
125
|
end
|
150
126
|
e.delete('alterrors')
|
151
127
|
end
|
152
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
128
|
+
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
153
129
|
|
154
130
|
if mhead['x-spasign'].to_s == 'NG'
|
155
131
|
# Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by EZweb)
|
@@ -157,17 +133,16 @@ module Sisimai::Lhost
|
|
157
133
|
e['reason'] = 'filtered'
|
158
134
|
else
|
159
135
|
if e['command'] == 'RCPT'
|
160
|
-
# set "userunknown" when the remote server rejected after RCPT
|
161
|
-
# command.
|
136
|
+
# set "userunknown" when the remote server rejected after RCPT command.
|
162
137
|
e['reason'] = 'userunknown'
|
163
138
|
else
|
164
139
|
# SMTP command is not RCPT
|
165
140
|
catch :SESSION do
|
166
141
|
ReFailures.each_key do |r|
|
167
|
-
#
|
142
|
+
# Try to match with each session error message
|
168
143
|
ReFailures[r].each do |rr|
|
169
|
-
# Check each
|
170
|
-
next unless e['diagnosis']
|
144
|
+
# Check each error message pattern
|
145
|
+
next unless e['diagnosis'].include?(rr)
|
171
146
|
e['reason'] = r
|
172
147
|
throw :SESSION
|
173
148
|
end
|
@@ -181,7 +156,7 @@ module Sisimai::Lhost
|
|
181
156
|
e['reason'] = 'userunknown'
|
182
157
|
end
|
183
158
|
|
184
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
159
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
185
160
|
end
|
186
161
|
def description; return 'au EZweb: http://www.au.kddi.com/mobile/'; end
|
187
162
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Facebook parses a bounce email which created by Facebook.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Facebook parses a bounce email which created by Facebook. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Facebook
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Facebook.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Disposition: inline'].freeze
|
11
10
|
StartingOf = { message: ['This message was created automatically by Facebook.'] }.freeze
|
12
11
|
ReFailures = {
|
13
12
|
# http://postmaster.facebook.com/response_codes
|
@@ -22,21 +21,20 @@ module Sisimai::Lhost
|
|
22
21
|
'RCP-P2', # The attempted recipient's preferences prevent messages from being delivered.
|
23
22
|
'RCP-P3', # The attempted recipient's privacy settings blocked the delivery.
|
24
23
|
],
|
25
|
-
'blocked' => [
|
26
|
-
'POL-P1', # Your mail server's IP Address is listed on the Spamhaus PBL.
|
27
|
-
'POL-P2', # Facebook will no longer accept mail from your mail server's IP Address.
|
28
|
-
],
|
29
24
|
'mesgtoobig' => [
|
30
25
|
'MSG-P1', # The message exceeds Facebook's maximum allowed size.
|
31
26
|
'INT-P2', # The message exceeds Facebook's maximum allowed size.
|
32
27
|
],
|
33
28
|
'contenterror' => [
|
34
29
|
'MSG-P2', # The message contains an attachment type that Facebook does not accept.
|
35
|
-
'MSG-P3', # The message contains multiple instances of a header field that can only be present once.
|
30
|
+
'MSG-P3', # The message contains multiple instances of a header field that can only be present once. Please see RFC 5322, section 3.6 for more information
|
36
31
|
'POL-P6', # The message contains a url that has been blocked by Facebook.
|
37
32
|
'POL-P7', # The message does not comply with Facebook's abuse policies and will not be accepted.
|
38
33
|
],
|
39
34
|
'securityerror' => [
|
35
|
+
'POL-P1', # Your mail server's IP Address is listed on the Spamhaus PBL.
|
36
|
+
'POL-P2', # Facebook will no longer accept mail from your mail server's IP Address.
|
37
|
+
'POL-P5', # The message contains a virus.
|
40
38
|
'POL-P7', # The message does not comply with Facebook's Domain Authentication requirements.
|
41
39
|
],
|
42
40
|
'notaccept' => [
|
@@ -55,20 +53,17 @@ module Sisimai::Lhost
|
|
55
53
|
],
|
56
54
|
'systemerror' => [
|
57
55
|
'CON-T1', # Facebook's mail server currently has too many connections open to allow another one.
|
58
|
-
'RCP-T1', # The attempted recipient address is not currently available due to an internal system issue. This is a temporary condition.
|
59
|
-
],
|
60
|
-
'virusdetected' => [
|
61
|
-
'POL-P5', # The message contains a virus.
|
62
56
|
],
|
63
57
|
'toomanyconn' => [
|
64
|
-
'CON-T2', # Your mail server currently has too many connections open to Facebook's mail servers.
|
65
58
|
'CON-T3', # Your mail server has opened too many new connections to Facebook's mail servers in a short period of time.
|
66
59
|
],
|
67
60
|
'suspend' => [
|
68
61
|
'RCP-T4', # The attempted recipient address is currently deactivated. The user may or may not reactivate it.
|
69
62
|
],
|
70
63
|
'undefined' => [
|
64
|
+
'RCP-T1', # The attempted recipient address is not currently available due to an internal system issue. This is a temporary condition.
|
71
65
|
'MSG-T1', # The number of recipients on the message exceeds Facebook's allowed maximum.
|
66
|
+
'CON-T2', # Your mail server currently has too many connections open to Facebook's mail servers.
|
72
67
|
'CON-T4', # Your mail server has exceeded the maximum number of recipients for its current connection.
|
73
68
|
],
|
74
69
|
}.freeze
|
@@ -78,17 +73,16 @@ module Sisimai::Lhost
|
|
78
73
|
# @param [String] mbody Message body of a bounce email
|
79
74
|
# @return [Hash] Bounce data list and message/rfc822 part
|
80
75
|
# @return [Nil] it failed to parse or the arguments are missing
|
81
|
-
def
|
76
|
+
def inquire(mhead, mbody)
|
82
77
|
return nil unless mhead['from'] == 'Facebook <mailer-daemon@mx.facebook.com>'
|
83
78
|
return nil unless mhead['subject'] == 'Sorry, your message could not be delivered'
|
84
79
|
|
85
|
-
require 'sisimai/rfc1894'
|
86
80
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
87
81
|
permessage = {} # (Hash) Store values of each Per-Message field
|
88
82
|
|
89
83
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
90
|
-
|
91
|
-
bodyslices =
|
84
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
85
|
+
bodyslices = emailparts[0].split("\n")
|
92
86
|
readslices = ['']
|
93
87
|
readcursor = 0 # (Integer) Points the current cursor position
|
94
88
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
@@ -96,8 +90,8 @@ module Sisimai::Lhost
|
|
96
90
|
v = nil
|
97
91
|
|
98
92
|
while e = bodyslices.shift do
|
99
|
-
# Read error messages and delivery status lines from the head of the email
|
100
|
-
#
|
93
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
94
|
+
# line of the beginning of the original message.
|
101
95
|
readslices << e # Save the current line for the next loop
|
102
96
|
|
103
97
|
if readcursor == 0
|
@@ -138,14 +132,14 @@ module Sisimai::Lhost
|
|
138
132
|
next unless fieldtable[o[0]]
|
139
133
|
v[fieldtable[o[0]]] = o[2]
|
140
134
|
|
141
|
-
next unless f
|
135
|
+
next unless f
|
142
136
|
permessage[fieldtable[o[0]]] = o[2]
|
143
137
|
end
|
144
138
|
else
|
145
139
|
# Continued line of the value of Diagnostic-Code field
|
146
140
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
147
|
-
next unless
|
148
|
-
v['diagnosis'] << ' ' <<
|
141
|
+
next unless e.start_with?(' ')
|
142
|
+
v['diagnosis'] << ' ' << e[e.rindex(' ') + 1, e.size]
|
149
143
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
150
144
|
end
|
151
145
|
end
|
@@ -155,14 +149,8 @@ module Sisimai::Lhost
|
|
155
149
|
e['lhost'] ||= permessage['lhost']
|
156
150
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
157
151
|
|
158
|
-
|
159
|
-
|
160
|
-
lhs = cv[1]
|
161
|
-
rhs = cv[2]
|
162
|
-
num = cv[3]
|
163
|
-
|
164
|
-
fbresponse = sprintf('%s-%s%d', lhs, rhs, num)
|
165
|
-
end
|
152
|
+
p0 = e['diagnosis'].index('-') || -1
|
153
|
+
fbresponse = e['diagnosis'][p0 - 3, 6] if p0 > 0
|
166
154
|
|
167
155
|
catch :SESSION do
|
168
156
|
ReFailures.each_key do |r|
|
@@ -188,11 +176,11 @@ module Sisimai::Lhost
|
|
188
176
|
# https://groups.google.com/forum/#!topic/cdmix/eXfi4ddgYLQ
|
189
177
|
# This block has not been tested because we have no email sample
|
190
178
|
# including "INT-T?" error code.
|
191
|
-
next unless fbresponse
|
179
|
+
next unless fbresponse.start_with?('INT-T')
|
192
180
|
e['reason'] = 'systemerror'
|
193
181
|
end
|
194
182
|
|
195
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
183
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
196
184
|
end
|
197
185
|
def description; return 'Facebook: https://www.facebook.com'; end
|
198
186
|
end
|
data/lib/sisimai/lhost/fml.rb
CHANGED
@@ -1,48 +1,41 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::FML parses a bounce email which created by fml.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::FML parses a bounce email which created by fml. Methods in the module are called
|
3
|
+
# from only Sisimai::Message.
|
4
4
|
module FML
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/FML.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Original mail as follows:'].freeze
|
11
10
|
ErrorTitle = {
|
12
|
-
'rejected' =>
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
}x,
|
26
|
-
'securityerror' => %r/Security Alert/,
|
11
|
+
'rejected' => [
|
12
|
+
' are not member',
|
13
|
+
'NOT MEMBER article from ',
|
14
|
+
'reject mail ',
|
15
|
+
'Spam mail from a spammer is rejected',
|
16
|
+
],
|
17
|
+
'systemerror' => [
|
18
|
+
'fml system error message',
|
19
|
+
'Loop Alert: ',
|
20
|
+
'Loop Back Warning: ',
|
21
|
+
'WARNING: UNIX FROM Loop',
|
22
|
+
],
|
23
|
+
'securityerror' => ['Security Alert'],
|
27
24
|
}.freeze
|
28
25
|
ErrorTable = {
|
29
|
-
'rejected' =>
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|Loop[ ]Back[ ]Warning:
|
43
|
-
)
|
44
|
-
}x,
|
45
|
-
'securityerror' => %r/Security alert:/,
|
26
|
+
'rejected' => [
|
27
|
+
' header may cause mail loop',
|
28
|
+
'NOT MEMBER article from ',
|
29
|
+
'reject mail from ',
|
30
|
+
'reject spammers:',
|
31
|
+
'You are not a member of this mailing list',
|
32
|
+
],
|
33
|
+
'systemerror' => [
|
34
|
+
' has detected a loop condition so that',
|
35
|
+
'Duplicated Message-ID',
|
36
|
+
'Loop Back Warning:',
|
37
|
+
],
|
38
|
+
'securityerror' => ['Security alert:'],
|
46
39
|
}.freeze
|
47
40
|
|
48
41
|
# Parse bounce messages from fml mailling list server/manager
|
@@ -51,34 +44,36 @@ module Sisimai::Lhost
|
|
51
44
|
# @return [Hash] Bounce data list and message/rfc822 part
|
52
45
|
# @return [Nil] it failed to parse or the arguments are missing
|
53
46
|
# @since v4.22.3
|
54
|
-
def
|
47
|
+
def inquire(mhead, mbody)
|
55
48
|
return nil unless mhead['x-mlserver']
|
56
|
-
return nil unless mhead['from']
|
57
|
-
return nil unless mhead['message-id']
|
49
|
+
return nil unless mhead['from'].include?('-admin@')
|
50
|
+
return nil unless mhead['message-id'].index('.FML') > 1
|
58
51
|
|
59
52
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
60
|
-
|
61
|
-
bodyslices =
|
53
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
54
|
+
bodyslices = emailparts[0].split("\n")
|
62
55
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
63
56
|
v = nil
|
64
57
|
|
65
58
|
while e = bodyslices.shift do
|
66
|
-
# Read error messages and delivery status lines from the head of the email
|
67
|
-
#
|
59
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
60
|
+
# line of the beginning of the original message.
|
68
61
|
next if e.empty?
|
69
62
|
|
70
63
|
# Duplicated Message-ID in <2ndml@example.com>.
|
71
64
|
# Original mail as follows:
|
72
65
|
v = dscontents[-1]
|
73
66
|
|
74
|
-
|
75
|
-
|
67
|
+
p1 = e.index('<') || -1
|
68
|
+
p2 = e.rindex('>') || -1
|
69
|
+
if p1 > 0 && p2 > 0
|
70
|
+
# You are not a member of this mailing list <neko-nyaan@example.org>.
|
76
71
|
if v['recipient']
|
77
72
|
# There are multiple recipient addresses in the message body.
|
78
73
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
79
74
|
v = dscontents[-1]
|
80
75
|
end
|
81
|
-
v['recipient'] =
|
76
|
+
v['recipient'] = e[p1 + 1, p2 - p1 - 1]
|
82
77
|
v['diagnosis'] = e
|
83
78
|
recipients += 1
|
84
79
|
else
|
@@ -94,7 +89,7 @@ module Sisimai::Lhost
|
|
94
89
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
95
90
|
ErrorTable.each_key do |f|
|
96
91
|
# Try to match with error messages defined in ErrorTable
|
97
|
-
next unless e['diagnosis']
|
92
|
+
next unless ErrorTable[f].any? { |a| e['diagnosis'].include?(a) }
|
98
93
|
e['reason'] = f
|
99
94
|
break
|
100
95
|
end
|
@@ -110,7 +105,7 @@ module Sisimai::Lhost
|
|
110
105
|
end
|
111
106
|
end
|
112
107
|
|
113
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
108
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
114
109
|
end
|
115
110
|
def description; return 'fml mailing list server/manager'; end
|
116
111
|
end
|
data/lib/sisimai/lhost/gmail.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Gmail parses a bounce email which created by Gmail.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Gmail parses a bounce email which created by Gmail. Methods in the module are
|
3
|
+
# called from only Sisimai::Message.
|
4
4
|
module Gmail
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Gmail.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['----- Original message -----', '----- Message header follows -----'].freeze
|
11
10
|
StartingOf = {
|
12
11
|
message: ['Delivery to the following recipient'],
|
13
12
|
error: ['The error that the other server returned was:'],
|
14
13
|
}.freeze
|
15
|
-
MarkingsOf = { start: %r/Technical details of (?:permanent|temporary) failure:/ }.freeze
|
16
14
|
MessagesOf = {
|
17
15
|
'expired' => [
|
18
16
|
'DNS Error: Could not contact DNS servers',
|
@@ -103,7 +101,7 @@ module Sisimai::Lhost
|
|
103
101
|
# @param [String] mbody Message body of a bounce email
|
104
102
|
# @return [Hash] Bounce data list and message/rfc822 part
|
105
103
|
# @return [Nil] it failed to parse or the arguments are missing
|
106
|
-
def
|
104
|
+
def inquire(mhead, mbody)
|
107
105
|
# From: Mail Delivery Subsystem <mailer-daemon@googlemail.com>
|
108
106
|
# Received: from vw-in-f109.1e100.net [74.125.113.109] by ...
|
109
107
|
#
|
@@ -154,16 +152,15 @@ module Sisimai::Lhost
|
|
154
152
|
return nil unless mhead['subject'].start_with?('Delivery Status Notification')
|
155
153
|
|
156
154
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
157
|
-
|
158
|
-
bodyslices =
|
155
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
156
|
+
bodyslices = emailparts[0].split("\n")
|
159
157
|
readcursor = 0 # (Integer) Points the current cursor position
|
160
158
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
161
|
-
statecode0 = 0 # (Integer) The value of (state *) in the error message
|
162
159
|
v = nil
|
163
160
|
|
164
161
|
while e = bodyslices.shift do
|
165
|
-
# Read error messages and delivery status lines from the head of the email
|
166
|
-
#
|
162
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
163
|
+
# line of the beginning of the original message.
|
167
164
|
if readcursor == 0
|
168
165
|
# Beginning of the bounce message or delivery status part
|
169
166
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -188,7 +185,7 @@ module Sisimai::Lhost
|
|
188
185
|
#
|
189
186
|
v = dscontents[-1]
|
190
187
|
|
191
|
-
if
|
188
|
+
if e.start_with?(' ') && e.include?('@')
|
192
189
|
# kijitora@example.jp: 550 5.2.2 <kijitora@example>... Mailbox Full
|
193
190
|
if v['recipient']
|
194
191
|
# There are multiple recipient addresses in the message body.
|
@@ -196,8 +193,8 @@ module Sisimai::Lhost
|
|
196
193
|
v = dscontents[-1]
|
197
194
|
end
|
198
195
|
|
199
|
-
r = Sisimai::Address.s3s4(
|
200
|
-
next unless Sisimai::
|
196
|
+
r = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
|
197
|
+
next unless Sisimai::Address.is_emailaddress(r)
|
201
198
|
v['recipient'] = r
|
202
199
|
recipients += 1
|
203
200
|
else
|
@@ -212,22 +209,24 @@ module Sisimai::Lhost
|
|
212
209
|
|
213
210
|
unless e['rhost']
|
214
211
|
# Get the value of remote host
|
215
|
-
if
|
216
|
-
# Google tried to deliver your message, but it was rejected by
|
217
|
-
#
|
218
|
-
|
219
|
-
|
220
|
-
e['
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
end
|
212
|
+
if Sisimai::String.aligned(e['diagnosis'], [' by ', '. [', ']. '])
|
213
|
+
# Google tried to deliver your message, but it was rejected by the server for the recipient
|
214
|
+
# domain example.jp by mx.example.jp. [192.0.2.153].
|
215
|
+
p1 = e['diagnosis'].rindex(' by ') || -1
|
216
|
+
p2 = e['diagnosis'].rindex('. [' ) || -1
|
217
|
+
hostname = e['diagnosis'][p1 + 4, p2 - p1 - 4]
|
218
|
+
ipv4addr = e['diagnosis'][p2 + 3, e['diagnosis'].rindex(']. ') - p2 - 3]
|
219
|
+
lastchar = hostname[-1, 1].upcase.ord
|
220
|
+
|
221
|
+
e['rhost'] = hostname if lastchar > 64 && lastchar < 91
|
222
|
+
e['rhost'] ||= ipv4addr
|
227
223
|
end
|
228
224
|
end
|
229
225
|
|
230
|
-
|
226
|
+
p1 = e['diagnosis'].rindex(' ') || -1
|
227
|
+
p2 = e['diagnosis'].rindex(')') || -1
|
228
|
+
statecode0 = e['diagnosis'][p1 + 1, p2 - p1 - 1] || 0
|
229
|
+
|
231
230
|
if StateTable[statecode0]
|
232
231
|
# (state *)
|
233
232
|
e['reason'] = StateTable[statecode0]['reason']
|
@@ -245,10 +244,11 @@ module Sisimai::Lhost
|
|
245
244
|
|
246
245
|
# Set pseudo status code
|
247
246
|
e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
|
248
|
-
|
247
|
+
next if e['status'].size == 0 || e['status'].include?('.0')
|
248
|
+
e['reason'] = Sisimai::SMTP::Status.name(e['status']).to_s || ''
|
249
249
|
end
|
250
250
|
|
251
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
251
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
252
252
|
end
|
253
253
|
def description; return 'Gmail: https://mail.google.com'; end
|
254
254
|
end
|