sisimai 4.22.3-java → 4.22.4-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sisimai might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Benchmarks.mk +54 -0
- data/ChangeLog.md +23 -2
- data/Developers.mk +42 -35
- data/Makefile +10 -0
- data/README-JA.md +13 -13
- data/README.md +14 -14
- data/lib/sisimai.rb +12 -18
- data/lib/sisimai/address.rb +64 -82
- data/lib/sisimai/arf.rb +27 -42
- data/lib/sisimai/bite/email.rb +2 -4
- data/lib/sisimai/bite/email/activehunter.rb +12 -17
- data/lib/sisimai/bite/email/amazonses.rb +30 -48
- data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
- data/lib/sisimai/bite/email/aol.rb +27 -35
- data/lib/sisimai/bite/email/apachejames.rb +17 -28
- data/lib/sisimai/bite/email/bigfoot.rb +20 -33
- data/lib/sisimai/bite/email/biglobe.rb +15 -24
- data/lib/sisimai/bite/email/courier.rb +37 -61
- data/lib/sisimai/bite/email/domino.rb +19 -28
- data/lib/sisimai/bite/email/einsundeins.rb +20 -34
- data/lib/sisimai/bite/email/exchange2003.rb +25 -43
- data/lib/sisimai/bite/email/exchange2007.rb +15 -23
- data/lib/sisimai/bite/email/exim.rb +101 -120
- data/lib/sisimai/bite/email/ezweb.rb +28 -44
- data/lib/sisimai/bite/email/facebook.rb +26 -37
- data/lib/sisimai/bite/email/fml.rb +11 -20
- data/lib/sisimai/bite/email/gmx.rb +17 -27
- data/lib/sisimai/bite/email/google.rb +19 -29
- data/lib/sisimai/bite/email/gsuite.rb +39 -48
- data/lib/sisimai/bite/email/imailserver.rb +25 -39
- data/lib/sisimai/bite/email/interscanmss.rb +19 -26
- data/lib/sisimai/bite/email/kddi.rb +20 -33
- data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
- data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
- data/lib/sisimai/bite/email/mailru.rb +40 -59
- data/lib/sisimai/bite/email/mcafee.rb +21 -35
- data/lib/sisimai/bite/email/messagelabs.rb +23 -38
- data/lib/sisimai/bite/email/messagingserver.rb +15 -27
- data/lib/sisimai/bite/email/mfilter.rb +19 -28
- data/lib/sisimai/bite/email/mxlogic.rb +31 -49
- data/lib/sisimai/bite/email/notes.rb +16 -24
- data/lib/sisimai/bite/email/office365.rb +29 -38
- data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
- data/lib/sisimai/bite/email/outlook.rb +24 -36
- data/lib/sisimai/bite/email/postfix.rb +33 -42
- data/lib/sisimai/bite/email/qmail.rb +44 -59
- data/lib/sisimai/bite/email/receivingses.rb +28 -36
- data/lib/sisimai/bite/email/sendgrid.rb +28 -37
- data/lib/sisimai/bite/email/sendmail.rb +35 -51
- data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
- data/lib/sisimai/bite/email/userdefined.rb +17 -28
- data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
- data/lib/sisimai/bite/email/verizon.rb +31 -56
- data/lib/sisimai/bite/email/x1.rb +11 -18
- data/lib/sisimai/bite/email/x2.rb +11 -23
- data/lib/sisimai/bite/email/x3.rb +10 -19
- data/lib/sisimai/bite/email/x4.rb +46 -65
- data/lib/sisimai/bite/email/x5.rb +26 -37
- data/lib/sisimai/bite/email/yahoo.rb +11 -19
- data/lib/sisimai/bite/email/yandex.rb +19 -30
- data/lib/sisimai/bite/email/zoho.rb +21 -30
- data/lib/sisimai/bite/json.rb +1 -2
- data/lib/sisimai/bite/json/amazonses.rb +20 -25
- data/lib/sisimai/bite/json/sendgrid.rb +1 -1
- data/lib/sisimai/data.rb +36 -55
- data/lib/sisimai/data/json.rb +3 -3
- data/lib/sisimai/data/yaml.rb +1 -1
- data/lib/sisimai/datetime.rb +5 -21
- data/lib/sisimai/mail.rb +4 -6
- data/lib/sisimai/mail/maildir.rb +1 -1
- data/lib/sisimai/mda.rb +41 -44
- data/lib/sisimai/message.rb +2 -3
- data/lib/sisimai/message/email.rb +42 -52
- data/lib/sisimai/message/json.rb +7 -7
- data/lib/sisimai/mime.rb +25 -23
- data/lib/sisimai/order/email.rb +2 -2
- data/lib/sisimai/order/json.rb +2 -7
- data/lib/sisimai/reason.rb +41 -46
- data/lib/sisimai/reason/blocked.rb +60 -71
- data/lib/sisimai/reason/contenterror.rb +4 -8
- data/lib/sisimai/reason/delivered.rb +1 -3
- data/lib/sisimai/reason/exceedlimit.rb +10 -20
- data/lib/sisimai/reason/expired.rb +5 -9
- data/lib/sisimai/reason/feedback.rb +1 -3
- data/lib/sisimai/reason/filtered.rb +19 -38
- data/lib/sisimai/reason/hasmoved.rb +5 -8
- data/lib/sisimai/reason/hostunknown.rb +11 -18
- data/lib/sisimai/reason/mailboxfull.rb +14 -24
- data/lib/sisimai/reason/mailererror.rb +3 -5
- data/lib/sisimai/reason/mesgtoobig.rb +15 -25
- data/lib/sisimai/reason/networkerror.rb +8 -10
- data/lib/sisimai/reason/norelaying.rb +9 -14
- data/lib/sisimai/reason/notaccept.rb +9 -21
- data/lib/sisimai/reason/onhold.rb +3 -8
- data/lib/sisimai/reason/policyviolation.rb +8 -10
- data/lib/sisimai/reason/rejected.rb +36 -49
- data/lib/sisimai/reason/securityerror.rb +11 -13
- data/lib/sisimai/reason/spamdetected.rb +23 -37
- data/lib/sisimai/reason/suspend.rb +9 -10
- data/lib/sisimai/reason/syntaxerror.rb +3 -4
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +2 -4
- data/lib/sisimai/reason/toomanyconn.rb +17 -30
- data/lib/sisimai/reason/undefined.rb +1 -3
- data/lib/sisimai/reason/userunknown.rb +28 -38
- data/lib/sisimai/reason/vacation.rb +4 -6
- data/lib/sisimai/reason/virusdetected.rb +4 -6
- data/lib/sisimai/rfc2606.rb +1 -2
- data/lib/sisimai/rfc3464.rb +87 -101
- data/lib/sisimai/rfc3834.rb +29 -39
- data/lib/sisimai/rfc5322.rb +17 -24
- data/lib/sisimai/rhost.rb +10 -7
- data/lib/sisimai/rhost/exchangeonline.rb +124 -255
- data/lib/sisimai/rhost/franceptt.rb +2 -2
- data/lib/sisimai/rhost/godaddy.rb +12 -25
- data/lib/sisimai/rhost/googleapps.rb +82 -183
- data/lib/sisimai/smtp.rb +4 -4
- data/lib/sisimai/smtp/error.rb +8 -8
- data/lib/sisimai/smtp/reply.rb +1 -1
- data/lib/sisimai/smtp/status.rb +1 -0
- data/lib/sisimai/string.rb +5 -7
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/README.md +1 -1
- data/set-of-emails/maildir/bsd/README.md +50 -50
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +4 -4
- data/lib/sisimai/skeleton.rb +0 -43
@@ -7,28 +7,15 @@ module Sisimai::Bite::Email
|
|
7
7
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/InterScanMSS.pm
|
8
8
|
require 'sisimai/bite/email'
|
9
9
|
|
10
|
-
Re0 = {
|
11
|
-
:from => %r/InterScan MSS/,
|
12
|
-
:received => %r/[ ][(]InterScanMSS[)][ ]with[ ]/,
|
13
|
-
:subject => [
|
14
|
-
'Mail could not be delivered',
|
15
|
-
# メッセージを配信できません。
|
16
|
-
'=?iso-2022-jp?B?GyRCJWElQyU7ITwlOCRyR1s/LiRHJC0kXiQ7JHMhIxsoQg==?=',
|
17
|
-
# メール配信に失敗しました
|
18
|
-
'=?iso-2022-jp?B?GyRCJWEhPCVrR1s/LiRLPDpHVCQ3JF4kNyQ/GyhCDQo=?=',
|
19
|
-
],
|
20
|
-
}.freeze
|
21
|
-
Re1 = {
|
22
|
-
:begin => %r|\AContent-type: text/plain|,
|
23
|
-
:rfc822 => %r|\AContent-type: message/rfc822|,
|
24
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
25
|
-
}.freeze
|
26
10
|
Indicators = Sisimai::Bite::Email.INDICATORS
|
11
|
+
StartingOf = {
|
12
|
+
message: ['Content-type: text/plain'],
|
13
|
+
rfc822: ['Content-type: message/rfc822'],
|
14
|
+
}.freeze
|
27
15
|
|
28
16
|
def description; return 'Trend Micro InterScan Messaging Security Suite'; end
|
29
17
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
30
18
|
def headerlist; return []; end
|
31
|
-
def pattern; return Re0; end
|
32
19
|
|
33
20
|
# Parse bounce messages from InterScanMSS
|
34
21
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -45,9 +32,17 @@ module Sisimai::Bite::Email
|
|
45
32
|
return nil unless mhead
|
46
33
|
return nil unless mbody
|
47
34
|
|
48
|
-
|
49
|
-
match
|
50
|
-
|
35
|
+
# :received => %r/[ ][(]InterScanMSS[)][ ]with[ ]/,
|
36
|
+
match = 0
|
37
|
+
tryto = [
|
38
|
+
'Mail could not be delivered',
|
39
|
+
# メッセージを配信できません。
|
40
|
+
'=?iso-2022-jp?B?GyRCJWElQyU7ITwlOCRyR1s/LiRHJC0kXiQ7JHMhIxsoQg==?=',
|
41
|
+
# メール配信に失敗しました
|
42
|
+
'=?iso-2022-jp?B?GyRCJWEhPCVrR1s/LiRLPDpHVCQ3JF4kNyQ/GyhCDQo=?=',
|
43
|
+
]
|
44
|
+
match += 1 if mhead['from'].include?('InterScan MSS')
|
45
|
+
match += 1 if tryto.find { |a| mhead['subject'] == a }
|
51
46
|
return nil if match.zero?
|
52
47
|
|
53
48
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
@@ -58,10 +53,10 @@ module Sisimai::Bite::Email
|
|
58
53
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
59
54
|
v = nil
|
60
55
|
|
61
|
-
hasdivided.
|
56
|
+
while e = hasdivided.shift do
|
62
57
|
if readcursor.zero?
|
63
58
|
# Beginning of the bounce message or delivery status part
|
64
|
-
if e
|
59
|
+
if e.start_with?(StartingOf[:message][0])
|
65
60
|
readcursor |= Indicators[:deliverystatus]
|
66
61
|
next
|
67
62
|
end
|
@@ -69,7 +64,7 @@ module Sisimai::Bite::Email
|
|
69
64
|
|
70
65
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
71
66
|
# Beginning of the original message part
|
72
|
-
if e
|
67
|
+
if e.start_with?(StartingOf[:rfc822][0])
|
73
68
|
readcursor |= Indicators[:'message-rfc822']
|
74
69
|
next
|
75
70
|
end
|
@@ -83,7 +78,6 @@ module Sisimai::Bite::Email
|
|
83
78
|
next
|
84
79
|
end
|
85
80
|
rfc822list << e
|
86
|
-
|
87
81
|
else
|
88
82
|
# Before "message/rfc822"
|
89
83
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -113,7 +107,6 @@ module Sisimai::Bite::Email
|
|
113
107
|
elsif cv = e.match(/\AReceived[ ]+[>]{3}[ ]+(\d{3}[ ]+.+)\z/)
|
114
108
|
# Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
|
115
109
|
v['diagnosis'] = cv[1]
|
116
|
-
|
117
110
|
else
|
118
111
|
# Error message in non-English
|
119
112
|
if cv = e.match(/[ ][>]{3}[ ]([A-Z]{4})/)
|
@@ -128,8 +121,8 @@ module Sisimai::Bite::Email
|
|
128
121
|
end
|
129
122
|
end
|
130
123
|
return nil if recipients.zero?
|
131
|
-
require 'sisimai/string'
|
132
124
|
|
125
|
+
require 'sisimai/string'
|
133
126
|
dscontents.map do |e|
|
134
127
|
e['agent'] = self.smtpagent
|
135
128
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
@@ -6,33 +6,24 @@ module Sisimai::Bite::Email
|
|
6
6
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/KDDI.pm
|
7
7
|
require 'sisimai/bite/email'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
:
|
13
|
-
:'message-id' => %r/[@].+[.]ezweb[.]ne[.]jp[>]\z/,
|
14
|
-
}.freeze
|
15
|
-
Re1 = {
|
16
|
-
:begin => %r/\AYour[ ]mail[ ](?:
|
9
|
+
Indicators = Sisimai::Bite::Email.INDICATORS
|
10
|
+
StartingOf = { rfc822: ['Content-Type: message/rfc822'] }.freeze
|
11
|
+
MarkingsOf = {
|
12
|
+
message: %r/\AYour[ ]mail[ ](?:
|
17
13
|
sent[ ]on:?[ ][A-Z][a-z]{2}[,]
|
18
14
|
|attempted[ ]to[ ]be[ ]delivered[ ]on:?[ ][A-Z][a-z]{2}[,]
|
19
15
|
)
|
20
16
|
/x,
|
21
|
-
:rfc822 => %r|\AContent-Type: message/rfc822\z|,
|
22
|
-
:error => %r/Could not be delivered to:? /,
|
23
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
24
17
|
}.freeze
|
25
|
-
|
26
|
-
mailboxfull: %r/As
|
27
|
-
norelaying: %r/Due
|
28
|
-
hostunknown: %r/As
|
18
|
+
ReFailures = {
|
19
|
+
mailboxfull: %r/As their mailbox is full/,
|
20
|
+
norelaying: %r/Due to the following SMTP relay error/,
|
21
|
+
hostunknown: %r/As the remote domain doesnt exist/,
|
29
22
|
}.freeze
|
30
|
-
Indicators = Sisimai::Bite::Email.INDICATORS
|
31
23
|
|
32
24
|
def description; return 'au by KDDI: http://www.au.kddi.com'; end
|
33
25
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
34
26
|
def headerlist; return []; end
|
35
|
-
def pattern; return Re0; end
|
36
27
|
|
37
28
|
# Parse bounce messages from au by KDDI
|
38
29
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -49,15 +40,15 @@ module Sisimai::Bite::Email
|
|
49
40
|
return nil unless mhead
|
50
41
|
return nil unless mbody
|
51
42
|
|
43
|
+
# :'message-id' => %r/[@].+[.]ezweb[.]ne[.]jp[>]\z/,
|
52
44
|
match = 0
|
53
|
-
match += 1 if mhead['from']
|
54
|
-
match += 1 if mhead['reply-to']
|
55
|
-
match += 1 if mhead['received'].find { |a| a
|
45
|
+
match += 1 if mhead['from'] =~ /no-reply[@].+[.]dion[.]ne[.]jp/
|
46
|
+
match += 1 if mhead['reply-to'].to_s == 'no-reply@app.auone-net.jp'
|
47
|
+
match += 1 if mhead['received'].find { |a| a.include?('ezweb.ne.jp (') }
|
56
48
|
return nil if match.zero?
|
57
49
|
|
58
50
|
require 'sisimai/string'
|
59
51
|
require 'sisimai/address'
|
60
|
-
|
61
52
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
62
53
|
hasdivided = mbody.split("\n")
|
63
54
|
rfc822list = [] # (Array) Each line in message/rfc822 part string
|
@@ -66,10 +57,10 @@ module Sisimai::Bite::Email
|
|
66
57
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
67
58
|
v = nil
|
68
59
|
|
69
|
-
hasdivided.
|
60
|
+
while e = hasdivided.shift do
|
70
61
|
if readcursor.zero?
|
71
62
|
# Beginning of the bounce message or delivery status part
|
72
|
-
if e =~
|
63
|
+
if e =~ MarkingsOf[:message]
|
73
64
|
readcursor |= Indicators[:deliverystatus]
|
74
65
|
next
|
75
66
|
end
|
@@ -77,7 +68,7 @@ module Sisimai::Bite::Email
|
|
77
68
|
|
78
69
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
79
70
|
# Beginning of the original message part
|
80
|
-
if e
|
71
|
+
if e == StartingOf[:rfc822][0]
|
81
72
|
readcursor |= Indicators[:'message-rfc822']
|
82
73
|
next
|
83
74
|
end
|
@@ -91,7 +82,6 @@ module Sisimai::Bite::Email
|
|
91
82
|
next
|
92
83
|
end
|
93
84
|
rfc822list << e
|
94
|
-
|
95
85
|
else
|
96
86
|
# Before "message/rfc822"
|
97
87
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -117,27 +107,24 @@ module Sisimai::Bite::Email
|
|
117
107
|
elsif cv = e.match(/Your mail sent on: (.+)\z/)
|
118
108
|
# Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
|
119
109
|
v['date'] = cv[1]
|
120
|
-
|
121
110
|
else
|
122
111
|
# As their mailbox is full.
|
123
112
|
v['diagnosis'] ||= ''
|
124
|
-
v['diagnosis']
|
113
|
+
v['diagnosis'] << e + ' ' if e.start_with?(' ', "\t")
|
125
114
|
end
|
126
115
|
end
|
127
116
|
end
|
128
|
-
|
129
117
|
return nil if recipients.zero?
|
130
|
-
require 'sisimai/smtp/status'
|
131
118
|
|
119
|
+
require 'sisimai/smtp/status'
|
132
120
|
dscontents.map do |e|
|
133
121
|
e['agent'] = self.smtpagent
|
134
122
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
135
123
|
|
136
|
-
if mhead['x-spasign']
|
124
|
+
if mhead['x-spasign'].to_s == 'NG'
|
137
125
|
# Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by KDDI)
|
138
126
|
# Filtered recipient returns message that include 'X-SPASIGN' header
|
139
127
|
e['reason'] = 'filtered'
|
140
|
-
|
141
128
|
else
|
142
129
|
if e['command'] == 'RCPT'
|
143
130
|
# set "userunknown" when the remote server rejected after RCPT
|
@@ -145,9 +132,9 @@ module Sisimai::Bite::Email
|
|
145
132
|
e['reason'] = 'userunknown'
|
146
133
|
else
|
147
134
|
# SMTP command is not RCPT
|
148
|
-
|
135
|
+
ReFailures.each_key do |r|
|
149
136
|
# Verify each regular expression of session errors
|
150
|
-
next unless e['diagnosis'] =~
|
137
|
+
next unless e['diagnosis'] =~ ReFailures[r]
|
151
138
|
e['reason'] = r.to_s
|
152
139
|
break
|
153
140
|
end
|
@@ -6,22 +6,16 @@ module Sisimai::Bite::Email
|
|
6
6
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/MailFoundry.pm
|
7
7
|
require 'sisimai/bite/email'
|
8
8
|
|
9
|
-
Re0 = {
|
10
|
-
:subject => %r/\AMessage delivery has failed\z/,
|
11
|
-
:received => %r/[(]MAILFOUNDRY[)] id /,
|
12
|
-
}.freeze
|
13
|
-
Re1 = {
|
14
|
-
:begin => %r/\AThis is a MIME encoded message\z/,
|
15
|
-
:error => %r/\ADelivery failed for the following reason:\z/,
|
16
|
-
:rfc822 => %r|\AContent-Type: message/rfc822\z|,
|
17
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
18
|
-
}.freeze
|
19
9
|
Indicators = Sisimai::Bite::Email.INDICATORS
|
10
|
+
StartingOf = {
|
11
|
+
message: ['This is a MIME encoded message'],
|
12
|
+
rfc822: ['Content-Type: message/rfc822'],
|
13
|
+
error: ['Delivery failed for the following reason:'],
|
14
|
+
}.freeze
|
20
15
|
|
21
16
|
def description; return 'MailFoundry'; end
|
22
17
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
23
18
|
def headerlist; return []; end
|
24
|
-
def pattern; return Re0; end
|
25
19
|
|
26
20
|
# Parse bounce messages from MailFoundry
|
27
21
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -37,8 +31,8 @@ module Sisimai::Bite::Email
|
|
37
31
|
def scan(mhead, mbody)
|
38
32
|
return nil unless mhead
|
39
33
|
return nil unless mbody
|
40
|
-
return nil unless mhead['subject']
|
41
|
-
return nil unless mhead['received'].find { |a| a
|
34
|
+
return nil unless mhead['subject'] == 'Message delivery has failed'
|
35
|
+
return nil unless mhead['received'].find { |a| a.include?('(MAILFOUNDRY) id ') }
|
42
36
|
|
43
37
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
44
38
|
hasdivided = mbody.split("\n")
|
@@ -48,10 +42,10 @@ module Sisimai::Bite::Email
|
|
48
42
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
49
43
|
v = nil
|
50
44
|
|
51
|
-
hasdivided.
|
45
|
+
while e = hasdivided.shift do
|
52
46
|
if readcursor.zero?
|
53
47
|
# Beginning of the bounce message or delivery status part
|
54
|
-
if e
|
48
|
+
if e == StartingOf[:message][0]
|
55
49
|
readcursor |= Indicators[:deliverystatus]
|
56
50
|
next
|
57
51
|
end
|
@@ -59,7 +53,7 @@ module Sisimai::Bite::Email
|
|
59
53
|
|
60
54
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
61
55
|
# Beginning of the original message part
|
62
|
-
if e
|
56
|
+
if e == StartingOf[:rfc822][0]
|
63
57
|
readcursor |= Indicators[:'message-rfc822']
|
64
58
|
next
|
65
59
|
end
|
@@ -73,7 +67,6 @@ module Sisimai::Bite::Email
|
|
73
67
|
next
|
74
68
|
end
|
75
69
|
rfc822list << e
|
76
|
-
|
77
70
|
else
|
78
71
|
# Before "message/rfc822"
|
79
72
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -95,29 +88,26 @@ module Sisimai::Bite::Email
|
|
95
88
|
end
|
96
89
|
v['recipient'] = cv[1]
|
97
90
|
recipients += 1
|
98
|
-
|
99
91
|
else
|
100
92
|
# Error message
|
101
|
-
if e
|
93
|
+
if e == StartingOf[:error][0]
|
102
94
|
# Delivery failed for the following reason:
|
103
95
|
v['diagnosis'] = e
|
104
|
-
|
105
96
|
else
|
106
97
|
# Detect error message
|
107
98
|
next if e.empty?
|
108
99
|
next if v['diagnosis'].nil? || v['diagnosis'].empty?
|
109
|
-
next if e
|
100
|
+
next if e.start_with?('-')
|
110
101
|
|
111
102
|
# Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
|
112
|
-
v['diagnosis']
|
113
|
-
v['diagnosis'] += ' ' + e
|
103
|
+
v['diagnosis'] << ' ' << e
|
114
104
|
end
|
115
105
|
end
|
116
106
|
end
|
117
107
|
end
|
118
108
|
return nil if recipients.zero?
|
119
|
-
require 'sisimai/string'
|
120
109
|
|
110
|
+
require 'sisimai/string'
|
121
111
|
dscontents.map do |e|
|
122
112
|
e['agent'] = self.smtpagent
|
123
113
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
@@ -7,22 +7,16 @@ module Sisimai::Bite::Email
|
|
7
7
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/MailMarshalSMTP.pm
|
8
8
|
require 'sisimai/bite/email'
|
9
9
|
|
10
|
-
Re0 = {
|
11
|
-
:subject => %r/\AUndeliverable Mail: ["]/,
|
12
|
-
}.freeze
|
13
|
-
Re1 = {
|
14
|
-
:begin => %r/\AYour message:\z/,
|
15
|
-
:rfc822 => nil,
|
16
|
-
:error => %r/\ACould not be delivered because of\z/,
|
17
|
-
:rcpts => %r/\AThe following recipients were affected:/,
|
18
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
19
|
-
}.freeze
|
20
10
|
Indicators = Sisimai::Bite::Email.INDICATORS
|
11
|
+
StartingOf = {
|
12
|
+
message: ['Your message:'],
|
13
|
+
error: ['Could not be delivered because of'],
|
14
|
+
rcpts: ['The following recipients were affected:'],
|
15
|
+
}.freeze
|
21
16
|
|
22
17
|
def description; return 'Trustwave Secure Email Gateway'; end
|
23
18
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
24
19
|
def headerlist; return ['X-Mailer']; end
|
25
|
-
def pattern; return Re0; end
|
26
20
|
|
27
21
|
# Parse bounce messages from MailMarshalSMTP
|
28
22
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -38,7 +32,7 @@ module Sisimai::Bite::Email
|
|
38
32
|
def scan(mhead, mbody)
|
39
33
|
return nil unless mhead
|
40
34
|
return nil unless mbody
|
41
|
-
return nil unless mhead['subject']
|
35
|
+
return nil unless mhead['subject'].start_with?('Undeliverable Mail: "')
|
42
36
|
|
43
37
|
require 'sisimai/mime'
|
44
38
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
@@ -54,15 +48,15 @@ module Sisimai::Bite::Email
|
|
54
48
|
boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
|
55
49
|
regularexp = if boundary00.size > 0
|
56
50
|
# Convert to regular expression
|
57
|
-
Regexp.new('\A'
|
51
|
+
Regexp.new('\A' << Regexp.escape('--' << boundary00 << '--') << '\z')
|
58
52
|
else
|
59
53
|
regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
|
60
54
|
end
|
61
55
|
|
62
|
-
hasdivided.
|
56
|
+
while e = hasdivided.shift do
|
63
57
|
if readcursor.zero?
|
64
58
|
# Beginning of the bounce message or delivery status part
|
65
|
-
if e
|
59
|
+
if e == StartingOf[:message][0]
|
66
60
|
readcursor |= Indicators[:deliverystatus]
|
67
61
|
next
|
68
62
|
end
|
@@ -84,7 +78,6 @@ module Sisimai::Bite::Email
|
|
84
78
|
next
|
85
79
|
end
|
86
80
|
rfc822list << e
|
87
|
-
|
88
81
|
else
|
89
82
|
# Before "message/rfc822"
|
90
83
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -112,21 +105,19 @@ module Sisimai::Bite::Email
|
|
112
105
|
end
|
113
106
|
v['recipient'] = cv[1]
|
114
107
|
recipients += 1
|
115
|
-
|
116
108
|
else
|
117
109
|
# Get error message lines
|
118
|
-
if e
|
110
|
+
if e == StartingOf[:error][0]
|
119
111
|
# Could not be delivered because of
|
120
112
|
#
|
121
113
|
# 550 5.1.1 User unknown
|
122
114
|
v['diagnosis'] = e
|
123
115
|
|
124
|
-
elsif v['diagnosis']
|
116
|
+
elsif v['diagnosis'].to_s.size > 0 && endoferror == false
|
125
117
|
# Append error messages
|
126
|
-
endoferror = true if e
|
118
|
+
endoferror = true if e.start_with?(StartingOf[:rcpts][0])
|
127
119
|
next if endoferror
|
128
|
-
v['diagnosis']
|
129
|
-
|
120
|
+
v['diagnosis'] << ' ' << e
|
130
121
|
else
|
131
122
|
# Additional Information
|
132
123
|
# ======================
|
@@ -140,7 +131,7 @@ module Sisimai::Bite::Email
|
|
140
131
|
# Original Sender: <originalsender@example.com>
|
141
132
|
# Use this line instead of "From" header of the original
|
142
133
|
# message.
|
143
|
-
rfc822list <<
|
134
|
+
rfc822list << ('From: ' << cv[1])
|
144
135
|
|
145
136
|
elsif cv = e.match(/\ASender-MTA:[ \t]+[<](.+)[>]\z/)
|
146
137
|
# Sender-MTA: <10.11.12.13>
|
@@ -155,8 +146,8 @@ module Sisimai::Bite::Email
|
|
155
146
|
end
|
156
147
|
end
|
157
148
|
return nil if recipients.zero?
|
158
|
-
require 'sisimai/string'
|
159
149
|
|
150
|
+
require 'sisimai/string'
|
160
151
|
dscontents.map do |e|
|
161
152
|
e['agent'] = self.smtpagent
|
162
153
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
@@ -7,36 +7,19 @@ module Sisimai::Bite::Email
|
|
7
7
|
# Based on Sisimai::Bite::Email::Exim
|
8
8
|
require 'sisimai/bite/email'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
:'message
|
13
|
-
:'
|
14
|
-
:'subject' => %r{(?:
|
15
|
-
Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
|
16
|
-
|Warning:[ ]message[ ].+[ ]delayed[ ]+
|
17
|
-
|Delivery[ ]Status[ ]Notification
|
18
|
-
|Mail[ ]failure
|
19
|
-
|Message[ ]frozen
|
20
|
-
|error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
|
21
|
-
)
|
22
|
-
}x,
|
23
|
-
}.freeze
|
24
|
-
Re1 = {
|
25
|
-
:rfc822 => %r/\A------ This is a copy of the message.+headers[.] ------\z/,
|
26
|
-
:begin => %r/\AThis message was created automatically by mail delivery software[.]/,
|
27
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
10
|
+
Indicators = Sisimai::Bite::Email.INDICATORS
|
11
|
+
StartingOf = {
|
12
|
+
message: ['This message was created automatically by mail delivery software.'],
|
13
|
+
rfc822: ['------ This is a copy of the message, including all the headers. ------'],
|
28
14
|
}.freeze
|
29
|
-
|
15
|
+
|
16
|
+
ReCommands = [
|
30
17
|
%r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
|
31
18
|
%r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
|
32
19
|
].freeze
|
33
|
-
|
34
|
-
expired:
|
35
|
-
|
36
|
-
|No[ ]action[ ]is[ ]required[ ]on[ ]your[ ]part
|
37
|
-
)
|
38
|
-
}x,
|
39
|
-
userunknown: %r/user[ ]not[ ]found/x,
|
20
|
+
ReFailures = {
|
21
|
+
expired: %r/(?:retry timeout exceeded|No action is required on your part)/,
|
22
|
+
userunknown: %r/user not found/,
|
40
23
|
hostunknown: %r{(?>
|
41
24
|
all[ ](?:
|
42
25
|
host[ ]address[ ]lookups[ ]failed[ ]permanently
|
@@ -45,25 +28,19 @@ module Sisimai::Bite::Email
|
|
45
28
|
|Unrouteable[ ]address
|
46
29
|
)
|
47
30
|
}x,
|
48
|
-
mailboxfull: %r/(?:mailbox
|
49
|
-
notaccept:
|
31
|
+
mailboxfull: %r/(?:mailbox is full:?|error: quota exceed)/,
|
32
|
+
notaccept: %r{(?:
|
50
33
|
an[ ]MX[ ]or[ ]SRV[ ]record[ ]indicated[ ]no[ ]SMTP[ ]service
|
51
34
|
|no[ ]host[ ]found[ ]for[ ]existing[ ]SMTP[ ]connection
|
52
35
|
)
|
53
36
|
}x,
|
54
|
-
systemerror:
|
55
|
-
|
56
|
-
|local[ ]delivery[ ]failed
|
57
|
-
)
|
58
|
-
}x,
|
59
|
-
contenterror: %r/Too[ ]many[ ]["]Received["][ ]headers[ ]/x,
|
37
|
+
systemerror: %r/(?:delivery to (?:file|pipe) forbidden|local delivery failed)/,
|
38
|
+
contenterror: %r/Too many ["]Received["] headers /,
|
60
39
|
}.freeze
|
61
|
-
Indicators = Sisimai::Bite::Email.INDICATORS
|
62
40
|
|
63
41
|
def description; return '@mail.ru: https://mail.ru'; end
|
64
42
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
65
43
|
def headerlist; return ['X-Failed-Recipients']; end
|
66
|
-
def pattern; return Re0; end
|
67
44
|
|
68
45
|
# Parse bounce messages from @mail.ru
|
69
46
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -79,9 +56,18 @@ module Sisimai::Bite::Email
|
|
79
56
|
def scan(mhead, mbody)
|
80
57
|
return nil unless mhead
|
81
58
|
return nil unless mbody
|
82
|
-
|
83
|
-
return nil unless mhead['
|
84
|
-
return nil unless mhead['message-id']
|
59
|
+
|
60
|
+
return nil unless mhead['from'] =~ /[<]?mailer-daemon[@].*mail[.]ru[>]?/i
|
61
|
+
return nil unless mhead['message-id'].end_with?('.mail.ru>')
|
62
|
+
return nil unless mhead['subject'] =~ %r{(?:
|
63
|
+
Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
|
64
|
+
|Warning:[ ]message[ ].+[ ]delayed[ ]+
|
65
|
+
|Delivery[ ]Status[ ]Notification
|
66
|
+
|Mail[ ]failure
|
67
|
+
|Message[ ]frozen
|
68
|
+
|error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
|
69
|
+
)
|
70
|
+
}x
|
85
71
|
|
86
72
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
87
73
|
hasdivided = mbody.split("\n")
|
@@ -92,10 +78,10 @@ module Sisimai::Bite::Email
|
|
92
78
|
localhost0 = '' # (String) Local MTA
|
93
79
|
v = nil
|
94
80
|
|
95
|
-
hasdivided.
|
81
|
+
while e = hasdivided.shift do
|
96
82
|
if readcursor.zero?
|
97
83
|
# Beginning of the bounce message or delivery status part
|
98
|
-
if e
|
84
|
+
if e.start_with?(StartingOf[:message][0])
|
99
85
|
readcursor |= Indicators[:deliverystatus]
|
100
86
|
next
|
101
87
|
end
|
@@ -103,7 +89,7 @@ module Sisimai::Bite::Email
|
|
103
89
|
|
104
90
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
105
91
|
# Beginning of the original message part
|
106
|
-
if e
|
92
|
+
if e == StartingOf[:rfc822][0]
|
107
93
|
readcursor |= Indicators[:'message-rfc822']
|
108
94
|
next
|
109
95
|
end
|
@@ -118,7 +104,6 @@ module Sisimai::Bite::Email
|
|
118
104
|
next
|
119
105
|
end
|
120
106
|
rfc822list << e
|
121
|
-
|
122
107
|
else
|
123
108
|
# Before "message/rfc822"
|
124
109
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -158,14 +143,13 @@ module Sisimai::Bite::Email
|
|
158
143
|
# Error message
|
159
144
|
next if e.empty?
|
160
145
|
v['diagnosis'] ||= ''
|
161
|
-
v['diagnosis']
|
162
|
-
|
146
|
+
v['diagnosis'] << e + ' '
|
163
147
|
else
|
164
148
|
# Error message when email address above does not include '@'
|
165
149
|
# and domain part.
|
166
|
-
next unless e
|
150
|
+
next unless e.start_with?(' ', "\t")
|
167
151
|
v['alterrors'] ||= ''
|
168
|
-
v['alterrors']
|
152
|
+
v['alterrors'] << e + ' '
|
169
153
|
end
|
170
154
|
end
|
171
155
|
end
|
@@ -178,7 +162,7 @@ module Sisimai::Bite::Email
|
|
178
162
|
rcptinhead.each { |a| a.delete(' ') }
|
179
163
|
recipients = rcptinhead.size
|
180
164
|
|
181
|
-
rcptinhead.
|
165
|
+
while e = rcptinhead.shift do
|
182
166
|
# Insert each recipient address into dscontents
|
183
167
|
dscontents[-1]['recipient'] = e
|
184
168
|
next if dscontents.size == recipients
|
@@ -201,10 +185,10 @@ module Sisimai::Bite::Email
|
|
201
185
|
# Set default values if each value is empty.
|
202
186
|
e['lhost'] ||= localhost0
|
203
187
|
|
204
|
-
if e['alterrors']
|
188
|
+
if e['alterrors'].to_s.size > 0
|
205
189
|
# Copy alternative error message
|
206
190
|
e['diagnosis'] ||= e['alterrors']
|
207
|
-
if e['diagnosis']
|
191
|
+
if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
|
208
192
|
# Override the value of diagnostic code message
|
209
193
|
e['diagnosis'] = e['alterrors'] if e['alterrors'].size > 0
|
210
194
|
end
|
@@ -221,16 +205,14 @@ module Sisimai::Bite::Email
|
|
221
205
|
end
|
222
206
|
|
223
207
|
unless e['rhost']
|
224
|
-
|
225
|
-
|
226
|
-
e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop
|
227
|
-
end
|
208
|
+
# Get localhost and remote host name from Received header.
|
209
|
+
e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop if mhead['received'].size > 0
|
228
210
|
end
|
229
211
|
end
|
230
212
|
|
231
213
|
unless e['command']
|
232
214
|
# Get the SMTP command name for the session
|
233
|
-
|
215
|
+
ReCommands.each do |r|
|
234
216
|
# Verify each regular expression of SMTP commands
|
235
217
|
if cv = e['diagnosis'].match(r)
|
236
218
|
e['command'] = cv[1].upcase
|
@@ -239,19 +221,18 @@ module Sisimai::Bite::Email
|
|
239
221
|
end
|
240
222
|
|
241
223
|
# Detect the reason of bounce
|
242
|
-
if e['command']
|
224
|
+
if %w[HELO EHLO].index(e['command'])
|
243
225
|
# HELO | Connected to 192.0.2.135 but my name was rejected.
|
244
226
|
e['reason'] = 'blocked'
|
245
227
|
|
246
228
|
elsif e['command'] == 'MAIL'
|
247
229
|
# MAIL | Connected to 192.0.2.135 but sender was rejected.
|
248
230
|
e['reason'] = 'rejected'
|
249
|
-
|
250
231
|
else
|
251
232
|
# Verify each regular expression of session errors
|
252
|
-
|
233
|
+
ReFailures.each_key do |r|
|
253
234
|
# Check each regular expression
|
254
|
-
next unless e['diagnosis'] =~
|
235
|
+
next unless e['diagnosis'] =~ ReFailures[r]
|
255
236
|
e['reason'] = r.to_s
|
256
237
|
break
|
257
238
|
end
|