sisimai 4.25.17 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +406 -407
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +12 -12
- data/README-JA.md +142 -94
- data/README.md +282 -150
- 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 +20 -16
- 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 -325
- 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 -45
- 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 +13 -18
- 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 -21
- 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/mac/reported-from-nick4tech-san-01.eml +0 -6
- /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
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MailFoundry parses a bounce email which created by
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::MailFoundry parses a bounce email which created by MailFoundry. Methods in the
|
3
|
+
# module are called from only Sisimai::Message.
|
4
4
|
module MailFoundry
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MailFoundry.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = {
|
12
11
|
message: ['Unable to deliver message to:'],
|
13
12
|
error: ['Delivery failed for the following reason:'],
|
@@ -18,20 +17,20 @@ module Sisimai::Lhost
|
|
18
17
|
# @param [String] mbody Message body of a bounce email
|
19
18
|
# @return [Hash] Bounce data list and message/rfc822 part
|
20
19
|
# @return [Nil] it failed to parse or the arguments are missing
|
21
|
-
def
|
20
|
+
def inquire(mhead, mbody)
|
22
21
|
return nil unless mhead['subject'] == 'Message delivery has failed'
|
23
22
|
return nil unless mhead['received'].any? { |a| a.include?('(MAILFOUNDRY) id ') }
|
24
23
|
|
25
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
26
|
-
|
27
|
-
bodyslices =
|
25
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
26
|
+
bodyslices = emailparts[0].split("\n")
|
28
27
|
readcursor = 0 # (Integer) Points the current cursor position
|
29
28
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
30
29
|
v = nil
|
31
30
|
|
32
31
|
while e = bodyslices.shift do
|
33
|
-
# Read error messages and delivery status lines from the head of the email
|
34
|
-
#
|
32
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
33
|
+
# line of the beginning of the original message.
|
35
34
|
if readcursor == 0
|
36
35
|
# Beginning of the bounce message or delivery status part
|
37
36
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -46,14 +45,14 @@ module Sisimai::Lhost
|
|
46
45
|
# This has been a permanent failure. No further delivery attempts will be made.
|
47
46
|
v = dscontents[-1]
|
48
47
|
|
49
|
-
if
|
48
|
+
if e.start_with?('Unable to deliver message to: <') && e.index('@') > 1
|
50
49
|
# Unable to deliver message to: <kijitora@example.org>
|
51
50
|
if v['recipient']
|
52
51
|
# There are multiple recipient addresses in the message body.
|
53
52
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
54
53
|
v = dscontents[-1]
|
55
54
|
end
|
56
|
-
v['recipient'] =
|
55
|
+
v['recipient'] = e[e.index('<'), e.size]
|
57
56
|
recipients += 1
|
58
57
|
else
|
59
58
|
# Error message
|
@@ -74,7 +73,7 @@ module Sisimai::Lhost
|
|
74
73
|
return nil unless recipients > 0
|
75
74
|
|
76
75
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
77
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
76
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
78
77
|
end
|
79
78
|
def description; return 'MailFoundry'; end
|
80
79
|
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MailMarshalSMTP parses a bounce email which created
|
3
|
-
#
|
4
|
-
# the module are called from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::MailMarshalSMTP parses a bounce email which created by Trustwave Secure Email
|
3
|
+
# Gateway: formerly MailMarshal SMTP. Methods in the module are called from only Sisimai::Message.
|
5
4
|
module MailMarshalSMTP
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MailMarshalSMTP.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++']
|
12
10
|
StartingOf = {
|
13
11
|
message: ['Your message:'],
|
14
12
|
error: ['Could not be delivered because of'],
|
@@ -20,26 +18,19 @@ module Sisimai::Lhost
|
|
20
18
|
# @param [String] mbody Message body of a bounce email
|
21
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
22
20
|
# @return [Nil] it failed to parse or the arguments are missing
|
23
|
-
def
|
21
|
+
def inquire(mhead, mbody)
|
24
22
|
return nil unless mhead['subject'].start_with?('Undeliverable Mail: "')
|
25
23
|
|
26
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
27
|
-
|
28
|
-
bodyslices =
|
25
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
26
|
+
bodyslices = emailparts[0].split("\n")
|
29
27
|
readcursor = 0 # (Integer) Points the current cursor position
|
30
28
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
31
29
|
endoferror = false # (Boolean) Flag for the end of error message
|
32
30
|
regularexp = nil
|
31
|
+
q = Sisimai::RFC2045.boundary(mhead['content-type'], 1); Boundaries << q if q
|
33
32
|
v = nil
|
34
33
|
|
35
|
-
boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
|
36
|
-
regularexp = if boundary00.size > 0
|
37
|
-
# Convert to regular expression
|
38
|
-
Regexp.new('\A' << Regexp.escape(boundary00) << '\z')
|
39
|
-
else
|
40
|
-
regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
|
41
|
-
end
|
42
|
-
|
43
34
|
while e = bodyslices.shift do
|
44
35
|
# Read error messages and delivery status lines from the head of the email
|
45
36
|
# to the previous line of the beginning of the original message.
|
@@ -61,7 +52,7 @@ module Sisimai::Lhost
|
|
61
52
|
# dummyuser@blabla.xxxxxxxxxxxx.com
|
62
53
|
v = dscontents[-1]
|
63
54
|
|
64
|
-
if
|
55
|
+
if e.start_with?(' ') && e.index('@') > 1
|
65
56
|
# The following recipients were affected:
|
66
57
|
# dummyuser@blabla.xxxxxxxxxxxx.com
|
67
58
|
if v['recipient']
|
@@ -69,7 +60,7 @@ module Sisimai::Lhost
|
|
69
60
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
70
61
|
v = dscontents[-1]
|
71
62
|
end
|
72
|
-
v['recipient'] =
|
63
|
+
v['recipient'] = e[4, e.size]
|
73
64
|
recipients += 1
|
74
65
|
else
|
75
66
|
# Get error message lines
|
@@ -93,24 +84,29 @@ module Sisimai::Lhost
|
|
93
84
|
# Reporting-MTA: <relay.xxxxxxxxxxxx.com>
|
94
85
|
# MessageName: <B549996730000.000000000001.0003.mml>
|
95
86
|
# Last-Attempt-Date: <16:21:07 seg, 22 Dezembro 2014>
|
96
|
-
|
87
|
+
p1 = e.index('<')
|
88
|
+
p2 = e.index('>')
|
89
|
+
if e.start_with?('Original Sender: ')
|
97
90
|
# Original Sender: <originalsender@example.com>
|
98
|
-
# Use this line instead of "From" header of the original
|
99
|
-
|
100
|
-
emailsteak[1] << ('From: ' << cv[1] << "\n")
|
91
|
+
# Use this line instead of "From" header of the original message.
|
92
|
+
emailparts[1] << ('From: ' << e[p1 + 1, p2 - p1 - 1] << "\n")
|
101
93
|
|
102
|
-
elsif
|
94
|
+
elsif e.start_with?('Sender-MTA: ')
|
103
95
|
# Sender-MTA: <10.11.12.13>
|
104
|
-
v['lhost'] =
|
96
|
+
v['lhost'] = e[p1 + 1, p2 - p1 - 1]
|
105
97
|
|
106
|
-
elsif
|
98
|
+
elsif e.start_with?('Reporting-MTA: ')
|
107
99
|
# Reporting-MTA: <relay.xxxxxxxxxxxx.com>
|
108
|
-
v['rhost'] =
|
100
|
+
v['rhost'] = e[p1 + 1, p2 - p1 - 1]
|
109
101
|
|
110
|
-
elsif
|
102
|
+
elsif e.include?(' From:') || e.include?(' Subject:')
|
111
103
|
# From: originalsender@example.com
|
112
104
|
# Subject: ...
|
113
|
-
|
105
|
+
p1 = e.index(' From:') || e.index(' Subject:')
|
106
|
+
p2 = e.index(':')
|
107
|
+
cf = e[p1 + 1, p2 - p1 - 1]
|
108
|
+
cv = Sisimai::String.sweep(e[p2 + 1, e.size])
|
109
|
+
emailparts[1] << sprintf("%s: %s\n", cf, cv)
|
114
110
|
end
|
115
111
|
end
|
116
112
|
end
|
@@ -118,7 +114,7 @@ module Sisimai::Lhost
|
|
118
114
|
return nil unless recipients > 0
|
119
115
|
|
120
116
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
121
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
117
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
122
118
|
end
|
123
119
|
def description; return 'Trustwave Secure Email Gateway'; end
|
124
120
|
end
|
data/lib/sisimai/lhost/mailru.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MailRu parses a bounce email which created by @mail.ru.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::MailRu parses a bounce email which created by @mail.ru. Methods in the module are
|
3
|
+
# called from only Sisimai::Message.
|
4
4
|
module MailRu
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MailRu.pm
|
7
6
|
# Based on Sisimai::Lhost::Exim
|
8
7
|
require 'sisimai/lhost'
|
9
8
|
|
10
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
10
|
+
Boundaries = ['------ This is a copy of the message, including all the headers. ------'].freeze
|
12
11
|
StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
|
13
12
|
ReCommands = [
|
14
13
|
%r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
|
@@ -50,30 +49,32 @@ module Sisimai::Lhost
|
|
50
49
|
# @param [String] mbody Message body of a bounce email
|
51
50
|
# @return [Hash] Bounce data list and message/rfc822 part
|
52
51
|
# @return [Nil] it failed to parse or the arguments are missing
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
52
|
+
def inquire(mhead, mbody)
|
53
|
+
mfrom = mhead['from'].downcase
|
54
|
+
msgid = mhead['message-id'] ? mhead['message-id'].downcase : ''
|
55
|
+
match = 0
|
56
|
+
match += 1 if mfrom.include?('mailer-daemon@') && mfrom.include?('mail.ru')
|
57
|
+
match += 1 if msgid.end_with?('.mail.ru>', 'smailru.net>')
|
58
|
+
match += 1 if [
|
59
|
+
'Delivery Status Notification',
|
60
|
+
'Mail delivery failed',
|
61
|
+
'Mail failure',
|
62
|
+
'Message frozen',
|
63
|
+
'Warning: message ',
|
64
|
+
'error(s) in forwarding or filtering'].any? { |a| mhead['subject'].include?(a) }
|
65
|
+
return nil unless match > 2
|
65
66
|
|
66
67
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
67
|
-
|
68
|
-
bodyslices =
|
68
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
69
|
+
bodyslices = emailparts[0].split("\n")
|
69
70
|
readcursor = 0 # (Integer) Points the current cursor position
|
70
71
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
71
72
|
localhost0 = '' # (String) Local MTA
|
72
73
|
v = nil
|
73
74
|
|
74
75
|
while e = bodyslices.shift do
|
75
|
-
# Read error messages and delivery status lines from the head of the email
|
76
|
-
#
|
76
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
77
|
+
# line of the beginning of the original message.
|
77
78
|
if readcursor == 0
|
78
79
|
# Beginning of the bounce message or delivery status part
|
79
80
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -102,14 +103,14 @@ module Sisimai::Lhost
|
|
102
103
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
103
104
|
v = dscontents[-1]
|
104
105
|
|
105
|
-
if
|
106
|
+
if e.start_with?(' ') && e.include?(' ') == false && e.index('@') > 1
|
106
107
|
# kijitora@example.jp
|
107
108
|
if v['recipient']
|
108
109
|
# There are multiple recipient addresses in the message body.
|
109
110
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
110
111
|
v = dscontents[-1]
|
111
112
|
end
|
112
|
-
v['recipient'] =
|
113
|
+
v['recipient'] = e[2, e.size]
|
113
114
|
recipients += 1
|
114
115
|
|
115
116
|
elsif dscontents.size == recipients
|
@@ -120,7 +121,7 @@ module Sisimai::Lhost
|
|
120
121
|
else
|
121
122
|
# Error message when email address above does not include '@'
|
122
123
|
# and domain part.
|
123
|
-
next unless e.start_with?(' '
|
124
|
+
next unless e.start_with?(' ')
|
124
125
|
v['alterrors'] ||= ''
|
125
126
|
v['alterrors'] << e + ' '
|
126
127
|
end
|
@@ -147,7 +148,9 @@ module Sisimai::Lhost
|
|
147
148
|
unless mhead['received'].empty?
|
148
149
|
# Get the name of local MTA
|
149
150
|
# Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
|
150
|
-
|
151
|
+
p1 = mhead['received'][-1].index('from ') || -1
|
152
|
+
p2 = mhead['received'][-1].index(' ', p1 + 5) || -1
|
153
|
+
localhost0 = mhead['received'][-1][p1 + 5, p2 - p1 - 5] if p1 > -1
|
151
154
|
end
|
152
155
|
|
153
156
|
dscontents.each do |e|
|
@@ -164,12 +167,15 @@ module Sisimai::Lhost
|
|
164
167
|
e.delete('alterrors')
|
165
168
|
end
|
166
169
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
167
|
-
e['diagnosis'].
|
170
|
+
p1 = e['diagnosis'].rindex('__') || -1
|
171
|
+
e['diagnosis'] = e['diagnosis'][0, p1 - 1] if p1 > 2
|
168
172
|
|
169
173
|
unless e['rhost']
|
170
174
|
# Get the remote host name
|
171
175
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
172
|
-
|
176
|
+
p1 = e['diagnosis'].index('host ') || -1
|
177
|
+
p2 = e['diagnosis'].index(' ', p1 + 5) || -1
|
178
|
+
e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
|
173
179
|
|
174
180
|
unless e['rhost']
|
175
181
|
# Get localhost and remote host name from Received header.
|
@@ -208,7 +214,7 @@ module Sisimai::Lhost
|
|
208
214
|
e['command'] ||= ''
|
209
215
|
end
|
210
216
|
|
211
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
217
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
212
218
|
end
|
213
219
|
def description; return '@mail.ru: https://mail.ru'; end
|
214
220
|
end
|
data/lib/sisimai/lhost/mcafee.rb
CHANGED
@@ -1,49 +1,39 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::McAfee parses a bounce email which created by McAfee
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::McAfee parses a bounce email which created by McAfee Email Appliance. Methods in
|
3
|
+
# the module are called from only Sisimai::Message.
|
4
4
|
module McAfee
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/McAfee.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = { message: ['--- The following addresses had delivery problems ---'] }.freeze
|
12
|
-
|
13
|
-
'userunknown' => %r{(?:
|
14
|
-
[ ]User[ ][(].+[@].+[)][ ]unknown[.][ ]
|
15
|
-
|550[ ]Unknown[ ]user[ ][^ ]+[@][^ ]+
|
16
|
-
|550[ ][<].+?[@].+?[>][.]+[ ]User[ ]not[ ]exist
|
17
|
-
|No[ ]such[ ]user
|
18
|
-
)
|
19
|
-
}x,
|
20
|
-
}.freeze
|
11
|
+
MessagesOf = { 'userunknown' => [' User not exist', ' unknown.', '550 Unknown user ', 'No such user'] }.freeze
|
21
12
|
|
22
13
|
# Parse bounce messages from McAfee Email Appliance
|
23
14
|
# @param [Hash] mhead Message headers of a bounce email
|
24
15
|
# @param [String] mbody Message body of a bounce email
|
25
16
|
# @return [Hash] Bounce data list and message/rfc822 part
|
26
17
|
# @return [Nil] it failed to parse or the arguments are missing
|
27
|
-
def
|
18
|
+
def inquire(mhead, mbody)
|
28
19
|
# X-NAI-Header: Modified by McAfee Email and Web Security Virtual Appliance
|
29
20
|
return nil unless mhead['x-nai-header']
|
30
21
|
return nil unless mhead['x-nai-header'].start_with?('Modified by McAfee ')
|
31
22
|
return nil unless mhead['subject'] == 'Delivery Status'
|
32
23
|
|
33
|
-
require 'sisimai/rfc1894'
|
34
24
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
35
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
36
|
-
|
37
|
-
bodyslices =
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
38
28
|
readslices = ['']
|
39
29
|
readcursor = 0 # (Integer) Points the current cursor position
|
40
30
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
41
|
-
|
31
|
+
issuedcode = '' # (String) Alternative diagnostic message
|
42
32
|
v = nil
|
43
33
|
|
44
34
|
while e = bodyslices.shift do
|
45
|
-
# Read error messages and delivery status lines from the head of the email
|
46
|
-
#
|
35
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
36
|
+
# line of the beginning of the original message.
|
47
37
|
readslices << e # Save the current line for the next loop
|
48
38
|
|
49
39
|
if readcursor == 0
|
@@ -65,15 +55,15 @@ module Sisimai::Lhost
|
|
65
55
|
#
|
66
56
|
v = dscontents[-1]
|
67
57
|
|
68
|
-
if
|
58
|
+
if Sisimai::String.aligned(e, ['<', '@', '>', '(', ')'])
|
69
59
|
# <kijitora@example.co.jp> (Unknown user kijitora@example.co.jp)
|
70
60
|
if v['recipient']
|
71
61
|
# There are multiple recipient addresses in the message body.
|
72
62
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
73
63
|
v = dscontents[-1]
|
74
64
|
end
|
75
|
-
v['recipient'] =
|
76
|
-
|
65
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.index('>')])
|
66
|
+
issuedcode = e[e.index('(') + 1, e.size]
|
77
67
|
recipients += 1
|
78
68
|
|
79
69
|
elsif f = Sisimai::RFC1894.match(e)
|
@@ -82,8 +72,8 @@ module Sisimai::Lhost
|
|
82
72
|
unless o
|
83
73
|
# Fallback code for empty value or invalid formatted value
|
84
74
|
# - Original-Recipient: <kijitora@example.co.jp>
|
85
|
-
if
|
86
|
-
v['alias'] = Sisimai::Address.s3s4(
|
75
|
+
if e.start_with?('Original-Recipient: ')
|
76
|
+
v['alias'] = Sisimai::Address.s3s4(e[e.index(':') + 1, e.size])
|
87
77
|
end
|
88
78
|
next
|
89
79
|
end
|
@@ -93,24 +83,24 @@ module Sisimai::Lhost
|
|
93
83
|
else
|
94
84
|
# Continued line of the value of Diagnostic-Code field
|
95
85
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
96
|
-
next unless
|
97
|
-
v['diagnosis'] << ' ' <<
|
86
|
+
next unless e.start_with?(' ')
|
87
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
98
88
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
99
89
|
end
|
100
90
|
end
|
101
91
|
return nil unless recipients > 0
|
102
92
|
|
103
93
|
dscontents.each do |e|
|
104
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] ||
|
105
|
-
|
94
|
+
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode)
|
95
|
+
MessagesOf.each_key do |r|
|
106
96
|
# Verify each regular expression of session errors
|
107
|
-
next unless e['diagnosis']
|
97
|
+
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
108
98
|
e['reason'] = r
|
109
99
|
break
|
110
100
|
end
|
111
101
|
end
|
112
102
|
|
113
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
103
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
114
104
|
end
|
115
105
|
def description; return 'McAfee Email Appliance'; end
|
116
106
|
end
|
@@ -1,18 +1,16 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MessageLabs parses a bounce email which created by
|
3
|
-
#
|
4
|
-
# from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::MessageLabs parses a bounce email which created by Symantec.cloud: formerly MessageLabs.
|
3
|
+
# Methods in the module are called from only Sisimai::Message.
|
5
4
|
module MessageLabs
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MessageLabs.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
12
10
|
StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
|
13
|
-
|
14
|
-
'userunknown' =>
|
15
|
-
'securityerror' =>
|
11
|
+
MessagesOf = {
|
12
|
+
'userunknown' => ['542 ', ' Rejected', 'No such user'],
|
13
|
+
'securityerror' => ['Please turn on SMTP Authentication in your mail client'],
|
16
14
|
}.freeze
|
17
15
|
|
18
16
|
# Parse bounce messages from Symantec.cloud(MessageLabs)
|
@@ -20,7 +18,7 @@ module Sisimai::Lhost
|
|
20
18
|
# @param [String] mbody Message body of a bounce email
|
21
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
22
20
|
# @return [Nil] it failed to parse or the arguments are missing
|
23
|
-
def
|
21
|
+
def inquire(mhead, mbody)
|
24
22
|
# X-Msg-Ref: server-11.tower-143.messagelabs.com!1419367175!36473369!1
|
25
23
|
# X-Originating-IP: [10.245.230.38]
|
26
24
|
# X-StarScan-Received:
|
@@ -30,13 +28,12 @@ module Sisimai::Lhost
|
|
30
28
|
return nil unless mhead['from'].include?('MAILER-DAEMON@messagelabs.com')
|
31
29
|
return nil unless mhead['subject'].start_with?('Mail Delivery Failure')
|
32
30
|
|
33
|
-
require 'sisimai/rfc1894'
|
34
31
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
35
32
|
permessage = {} # (Hash) Store values of each Per-Message field
|
36
33
|
|
37
34
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
38
|
-
|
39
|
-
bodyslices =
|
35
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
36
|
+
bodyslices = emailparts[0].split("\n")
|
40
37
|
readslices = ['']
|
41
38
|
readcursor = 0 # (Integer) Points the current cursor position
|
42
39
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
@@ -44,8 +41,8 @@ module Sisimai::Lhost
|
|
44
41
|
v = nil
|
45
42
|
|
46
43
|
while e = bodyslices.shift do
|
47
|
-
# Read error messages and delivery status lines from the head of the email
|
48
|
-
#
|
44
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
45
|
+
# line of the beginning of the original message.
|
49
46
|
readslices << e # Save the current line for the next loop
|
50
47
|
|
51
48
|
if readcursor == 0
|
@@ -86,14 +83,14 @@ module Sisimai::Lhost
|
|
86
83
|
next unless fieldtable[o[0]]
|
87
84
|
v[fieldtable[o[0]]] = o[2]
|
88
85
|
|
89
|
-
next unless f
|
86
|
+
next unless f
|
90
87
|
permessage[fieldtable[o[0]]] = o[2]
|
91
88
|
end
|
92
89
|
else
|
93
90
|
# Continued line of the value of Diagnostic-Code field
|
94
91
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
95
|
-
next unless
|
96
|
-
v['diagnosis'] << ' ' <<
|
92
|
+
next unless e.start_with?(' ')
|
93
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
97
94
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
98
95
|
end
|
99
96
|
end
|
@@ -106,15 +103,15 @@ module Sisimai::Lhost
|
|
106
103
|
e['command'] = commandset.shift || ''
|
107
104
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
108
105
|
|
109
|
-
|
106
|
+
MessagesOf.each_key do |r|
|
110
107
|
# Verify each regular expression of session errors
|
111
|
-
next unless e['diagnosis']
|
108
|
+
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
112
109
|
e['reason'] = r
|
113
110
|
break
|
114
111
|
end
|
115
112
|
end
|
116
113
|
|
117
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
114
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
118
115
|
end
|
119
116
|
def description; return 'Symantec.cloud http://www.messagelabs.com'; end
|
120
117
|
end
|