sisimai 4.25.16 → 5.0.1
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 +424 -393
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +323 -149
- data/README.md +319 -148
- 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 -326
- 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/google.rb +530 -0
- 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 +507 -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 +46 -31
- 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/lib/sisimai/rhost/googleapps.rb +0 -261
- /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,14 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MessagingServer parses a bounce email which created
|
3
|
-
#
|
4
|
-
# Server. Methods in the module are called from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::MessagingServer parses a bounce email which created by Oracle Communications Messaging
|
3
|
+
# Server and Sun Java System Messaging Server. Methods in the module are called from only Sisimai::Message.
|
5
4
|
module MessagingServer
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MessagingServer.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822', 'Return-path: '].freeze
|
12
10
|
StartingOf = { message: ['This report relates to a message you sent with the following header fields:'] }.freeze
|
13
11
|
MessagesOf = { 'hostunknown' => ['Illegal host/domain name found'] }.freeze
|
14
12
|
|
@@ -17,23 +15,22 @@ module Sisimai::Lhost
|
|
17
15
|
# @param [String] mbody Message body of a bounce email
|
18
16
|
# @return [Hash] Bounce data list and message/rfc822 part
|
19
17
|
# @return [Nil] it failed to parse or the arguments are missing
|
20
|
-
def
|
21
|
-
# :received => %r/[ ][(]MessagingServer[)][ ]with[ ]/,
|
18
|
+
def inquire(mhead, mbody)
|
22
19
|
match = 0
|
23
20
|
match += 1 if mhead['content-type'].include?('Boundary_(ID_')
|
24
21
|
match += 1 if mhead['subject'].start_with?('Delivery Notification: ')
|
25
22
|
return nil unless match > 0
|
26
23
|
|
27
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
28
|
-
|
29
|
-
bodyslices =
|
25
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
26
|
+
bodyslices = emailparts[0].split("\n")
|
30
27
|
readcursor = 0 # (Integer) Points the current cursor position
|
31
28
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
32
29
|
v = nil
|
33
30
|
|
34
31
|
while e = bodyslices.shift do
|
35
|
-
# Read error messages and delivery status lines from the head of the email
|
36
|
-
#
|
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.
|
37
34
|
if readcursor == 0
|
38
35
|
# Beginning of the bounce message or delivery status part
|
39
36
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -62,45 +59,49 @@ module Sisimai::Lhost
|
|
62
59
|
# Remote system: dns;mx.example.jp (TCP|17.111.174.67|47323|192.0.2.225|25) (6jo.example.jp ESMTP SENDMAIL-VM)
|
63
60
|
v = dscontents[-1]
|
64
61
|
|
65
|
-
if
|
62
|
+
if e.start_with?(' Recipient address: ') && e.index('@') > 1
|
66
63
|
# Recipient address: kijitora@example.jp
|
67
64
|
if v['recipient']
|
68
65
|
# There are multiple recipient addresses in the message body.
|
69
66
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
70
67
|
v = dscontents[-1]
|
71
68
|
end
|
72
|
-
v['recipient'] = Sisimai::Address.s3s4(
|
69
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
|
73
70
|
recipients += 1
|
74
71
|
|
75
|
-
elsif
|
72
|
+
elsif e.start_with?(' Original address: ') && e.index('@') > 1
|
76
73
|
# Original address: kijitora@example.jp
|
77
|
-
v['recipient'] = Sisimai::Address.s3s4(
|
74
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
|
78
75
|
|
79
|
-
elsif
|
76
|
+
elsif e.start_with?(' Date: ')
|
80
77
|
# Date: Fri, 21 Nov 2014 23:34:45 +0900
|
81
|
-
v['date'] =
|
78
|
+
v['date'] = e[e.index(':') + 2, e.size]
|
82
79
|
|
83
|
-
elsif
|
80
|
+
elsif e.start_with?(' Reason: ')
|
84
81
|
# Reason: Remote SMTP server has rejected address
|
85
|
-
v['diagnosis'] =
|
82
|
+
v['diagnosis'] = e[e.index(':') + 2, e.size]
|
86
83
|
|
87
|
-
elsif
|
84
|
+
elsif e.start_with?(' Diagnostic code: ')
|
88
85
|
# Diagnostic code: smtp;550 5.1.1 <kijitora@example.jp>... User Unknown
|
89
|
-
|
90
|
-
|
86
|
+
p1 = e.index(':')
|
87
|
+
p2 = e.index(';')
|
88
|
+
v['spec'] = e[p1 + 2, p2 - p1 - 2].upcase
|
89
|
+
v['diagnosis'] = e[p2 + 1, e.size]
|
91
90
|
|
92
|
-
elsif
|
91
|
+
elsif e.start_with?(' Remote system: ')
|
93
92
|
# Remote system: dns;mx.example.jp (TCP|17.111.174.67|47323|192.0.2.225|25)
|
94
93
|
# (6jo.example.jp ESMTP SENDMAIL-VM)
|
95
|
-
|
96
|
-
|
94
|
+
p1 = e.index(';')
|
95
|
+
p2 = e.index('(')
|
96
|
+
remotehost = e[p1 + 1, p2 - p1 - 2]
|
97
|
+
sessionlog = e[p2, e.size].split('|')
|
97
98
|
v['rhost'] = remotehost
|
98
99
|
|
99
100
|
# The value does not include ".", use IP address instead.
|
100
101
|
# (TCP|17.111.174.67|47323|192.0.2.225|25)
|
101
|
-
next unless
|
102
|
-
v['lhost'] =
|
103
|
-
v['rhost'] =
|
102
|
+
next unless sessionlog[0] == '(TCP'
|
103
|
+
v['lhost'] = sessionlog[1]
|
104
|
+
v['rhost'] = sessionlog[3] unless remotehost.index('.') > 1
|
104
105
|
else
|
105
106
|
# Original-envelope-id: 0NFC009FLKOUVMA0@mr21p30im-asmtp004.me.com
|
106
107
|
# Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon)
|
@@ -114,20 +115,22 @@ module Sisimai::Lhost
|
|
114
115
|
# (6jo.example.jp ESMTP SENDMAIL-VM)
|
115
116
|
# Diagnostic-code: smtp;550 5.1.1 <kijitora@example.jp>... User Unknown
|
116
117
|
#
|
117
|
-
if
|
118
|
+
if e.start_with?('Status: ')
|
118
119
|
# Status: 5.1.1 (Remote SMTP server has rejected address)
|
119
|
-
|
120
|
-
|
120
|
+
p1 = e.index(':')
|
121
|
+
p2 = e.index('(')
|
122
|
+
v['status'] = e[p1 + 2, p2 - p1 - 3]
|
123
|
+
v['diagnosis'] ||= e[p2 + 1, e[e.index(')') - p2 - 1]]
|
121
124
|
|
122
|
-
elsif
|
125
|
+
elsif e.start_with?('Arrival-Date: ')
|
123
126
|
# Arrival-date: Thu, 29 Apr 2014 23:34:45 +0000 (GMT)
|
124
|
-
v['date'] ||=
|
127
|
+
v['date'] ||= e[e.index(':') + 2, e.size]
|
125
128
|
|
126
|
-
elsif
|
129
|
+
elsif e.start_with?('Reporting-MTA: ')
|
127
130
|
# Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon)
|
128
|
-
localhost =
|
131
|
+
localhost = e[e.index(';') + 1, e.size]
|
129
132
|
v['lhost'] ||= localhost
|
130
|
-
v['lhost'] = localhost unless v['lhost']
|
133
|
+
v['lhost'] = localhost unless v['lhost'].index('.') > 0
|
131
134
|
end
|
132
135
|
end
|
133
136
|
end
|
@@ -143,7 +146,7 @@ module Sisimai::Lhost
|
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
146
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
149
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
147
150
|
end
|
148
151
|
def description; return 'Oracle Communications Messaging Server'; end
|
149
152
|
end
|
@@ -1,44 +1,43 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::mFILTER parses a bounce email which created by
|
3
|
-
#
|
4
|
-
# Methods in the module are called from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::mFILTER parses a bounce email which created by Digital Arts m-FILTER. Methods in
|
3
|
+
# the module are called from only Sisimai::Message.
|
5
4
|
module MFILTER
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/mFILTER.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['-------original message', '-------original mail info'].freeze
|
12
10
|
StartingOf = {
|
13
11
|
error: ['-------server message'],
|
14
12
|
command: ['-------SMTP command'],
|
15
13
|
}.freeze
|
16
|
-
MarkingsOf = { message: %r/\A[^ ]+[@][^ ]+[.][a-zA-Z]+\z/ }.freeze
|
17
14
|
|
18
15
|
# Parse bounce messages from Digital Arts m-FILTER
|
19
16
|
# @param [Hash] mhead Message headers of a bounce email
|
20
17
|
# @param [String] mbody Message body of a bounce email
|
21
18
|
# @return [Hash] Bounce data list and message/rfc822 part
|
22
19
|
# @return [Nil] it failed to parse or the arguments are missing
|
23
|
-
def
|
20
|
+
def inquire(mhead, mbody)
|
24
21
|
# X-Mailer: m-FILTER
|
25
22
|
return nil unless mhead['x-mailer'].to_s == 'm-FILTER'
|
26
23
|
return nil unless mhead['subject'] == 'failure notice'
|
27
24
|
|
28
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
29
|
-
|
30
|
-
bodyslices =
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
31
28
|
readcursor = 0 # (Integer) Points the current cursor position
|
32
29
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
33
30
|
markingset = { 'diagnosis' => false, 'command' => false }
|
34
31
|
v = nil
|
35
32
|
|
36
33
|
while e = bodyslices.shift do
|
37
|
-
# Read error messages and delivery status lines from the head of the email
|
38
|
-
#
|
34
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
35
|
+
# line of the beginning of the original message.
|
39
36
|
if readcursor == 0
|
40
37
|
# Beginning of the bounce message or delivery status part
|
41
|
-
|
38
|
+
if e.include?('@') && e.include?(' ') == false && Sisimai::Address.is_emailaddress(e)
|
39
|
+
readcursor |= Indicators[:deliverystatus]
|
40
|
+
end
|
42
41
|
end
|
43
42
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
44
43
|
next if e.empty?
|
@@ -60,7 +59,7 @@ module Sisimai::Lhost
|
|
60
59
|
# -------original message
|
61
60
|
v = dscontents[-1]
|
62
61
|
|
63
|
-
if
|
62
|
+
if e.include?('@') && e.include?(' ') == false
|
64
63
|
# 以下のメールアドレスへの送信に失敗しました。
|
65
64
|
# kijitora@example.jp
|
66
65
|
if v['recipient']
|
@@ -68,10 +67,10 @@ module Sisimai::Lhost
|
|
68
67
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
69
68
|
v = dscontents[-1]
|
70
69
|
end
|
71
|
-
v['recipient'] =
|
70
|
+
v['recipient'] = e
|
72
71
|
recipients += 1
|
73
72
|
|
74
|
-
elsif e
|
73
|
+
elsif e.size == 4 && e.index(' ').nil?
|
75
74
|
# -------SMTP command
|
76
75
|
# DATA
|
77
76
|
next if v['command']
|
@@ -111,7 +110,7 @@ module Sisimai::Lhost
|
|
111
110
|
e['rhost'] = ee
|
112
111
|
end
|
113
112
|
end
|
114
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
113
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
115
114
|
end
|
116
115
|
def description; return 'Digital Arts m-FILTER'; end
|
117
116
|
end
|
@@ -1,22 +1,20 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MXLogic parses a bounce email which created by
|
3
|
-
# McAfee SaaS (formerly MX Logic).
|
2
|
+
# Sisimai::Lhost::MXLogic parses a bounce email which created by McAfee SaaS (formerly MX Logic).
|
4
3
|
# Methods in the module are called from only Sisimai::Message.
|
5
4
|
module MXLogic
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MXLogic.pm
|
8
6
|
# Based on Sisimai::Lhost::Exim
|
9
7
|
require 'sisimai/lhost'
|
10
8
|
|
11
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
12
|
-
|
10
|
+
Boundaries = ['Included is a copy of the message header:'].freeze
|
13
11
|
StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
|
14
12
|
ReCommands = [
|
15
13
|
%r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
|
16
14
|
%r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
|
17
15
|
].freeze
|
18
16
|
MessagesOf = {
|
19
|
-
# find exim/ -type f -exec grep 'message = US' {} /dev/null \;
|
17
|
+
# % find exim/ -type f -exec grep 'message = US' {} /dev/null \;
|
20
18
|
# route.c:1158| DEBUG(D_uid) debug_printf("getpwnam() returned NULL (user not found)\n");
|
21
19
|
'userunknown' => ['user not found'],
|
22
20
|
# transports/smtp.c:3524| addr->message = US"all host address lookups failed permanently";
|
@@ -74,7 +72,7 @@ module Sisimai::Lhost
|
|
74
72
|
# @param [String] mbody Message body of a bounce email
|
75
73
|
# @return [Hash] Bounce data list and message/rfc822 part
|
76
74
|
# @return [Nil] it failed to parse or the arguments are missing
|
77
|
-
def
|
75
|
+
def inquire(mhead, mbody)
|
78
76
|
# X-MX-Bounce: mta/src/queue/bounce
|
79
77
|
# X-MXL-NoteHash: ffffffffffffffff-0000000000000000000000000000000000000000
|
80
78
|
# X-MXL-Hash: 4c9d4d411993da17-bbd4212b6c887f6c23bab7db4bd87ef5edc00758
|
@@ -83,25 +81,20 @@ module Sisimai::Lhost
|
|
83
81
|
match += 1 if mhead['x-mxl-hash']
|
84
82
|
match += 1 if mhead['x-mxl-notehash']
|
85
83
|
match += 1 if mhead['from'].start_with?('Mail Delivery System')
|
86
|
-
match += 1 if mhead['subject']
|
87
|
-
Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
|
88
|
-
|Warning:[ ]message[ ][^ ]+[ ]delayed[ ]+
|
89
|
-
|Delivery[ ]Status[ ]Notification
|
90
|
-
)
|
91
|
-
}x
|
84
|
+
match += 1 if ['Delivery Status Notification', 'Mail delivery failed', 'Warning: message '].any? { |a| mhead['subject'].include?(a) }
|
92
85
|
return nil unless match > 0
|
93
86
|
|
94
87
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
95
|
-
|
96
|
-
bodyslices =
|
88
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
89
|
+
bodyslices = emailparts[0].split("\n")
|
97
90
|
readcursor = 0 # (Integer) Points the current cursor position
|
98
91
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
99
92
|
localhost0 = '' # (String) Local MTA
|
100
93
|
v = nil
|
101
94
|
|
102
95
|
while e = bodyslices.shift do
|
103
|
-
# Read error messages and delivery status lines from the head of the email
|
104
|
-
#
|
96
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
97
|
+
# line of the beginning of the original message.
|
105
98
|
if readcursor == 0
|
106
99
|
# Beginning of the bounce message or delivery status part
|
107
100
|
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
@@ -120,7 +113,7 @@ module Sisimai::Lhost
|
|
120
113
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
121
114
|
v = dscontents[-1]
|
122
115
|
|
123
|
-
if
|
116
|
+
if e.start_with?(' <') && e.include?('@') && e.include?('>:')
|
124
117
|
# A message that you have sent could not be delivered to one or more
|
125
118
|
# recipients. This is a permanent error. The following address failed:
|
126
119
|
#
|
@@ -130,8 +123,8 @@ module Sisimai::Lhost
|
|
130
123
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
131
124
|
v = dscontents[-1]
|
132
125
|
end
|
133
|
-
v['recipient'] =
|
134
|
-
v['diagnosis'] =
|
126
|
+
v['recipient'] = e[3, e.index('>:') - 3]
|
127
|
+
v['diagnosis'] = e[e.index('>:') + 3, e.size]
|
135
128
|
recipients += 1
|
136
129
|
|
137
130
|
elsif dscontents.size == recipients
|
@@ -144,8 +137,13 @@ module Sisimai::Lhost
|
|
144
137
|
|
145
138
|
unless mhead['received'].empty?
|
146
139
|
# Get the name of local MTA
|
147
|
-
|
148
|
-
|
140
|
+
p1 = mhead['received'][-1].downcase.index('from ')
|
141
|
+
p2 = mhead['received'][-1].index(' ', p1 + 5)
|
142
|
+
|
143
|
+
if (p1 + 1) * (p2 + 1) > 0
|
144
|
+
# Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
|
145
|
+
localhost0 = mhead['received'][-1][p1 + 5, p2 - p1 - 5]
|
146
|
+
end
|
149
147
|
end
|
150
148
|
|
151
149
|
dscontents.each do |e|
|
@@ -154,8 +152,11 @@ module Sisimai::Lhost
|
|
154
152
|
|
155
153
|
unless e['rhost']
|
156
154
|
# Get the remote host name
|
155
|
+
p1 = e['diagnosis'].index('host ') || -1
|
156
|
+
p2 = e['diagnosis'].index(' ', p1 + 5)
|
157
|
+
|
157
158
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
158
|
-
|
159
|
+
e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
|
159
160
|
|
160
161
|
unless e['rhost']
|
161
162
|
# Get localhost and remote host name from Received header.
|
@@ -198,7 +199,7 @@ module Sisimai::Lhost
|
|
198
199
|
end
|
199
200
|
end
|
200
201
|
|
201
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
202
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
202
203
|
end
|
203
204
|
def description; return 'McAfee SaaS'; end
|
204
205
|
end
|
data/lib/sisimai/lhost/notes.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Notes parses a bounce email which created by Lotus
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Notes parses a bounce email which created by Lotus Notes Server. Methods in the
|
3
|
+
# module are called from only Sisimai::Message.
|
4
4
|
module Notes
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Notes.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['------- Returned Message --------'].freeze
|
11
10
|
StartingOf = { message: ['------- Failure Reasons '] }.freeze
|
12
11
|
MessagesOf = {
|
13
12
|
'userunknown' => [
|
@@ -22,12 +21,12 @@ module Sisimai::Lhost
|
|
22
21
|
# @param [String] mbody Message body of a bounce email
|
23
22
|
# @return [Hash] Bounce data list and message/rfc822 part
|
24
23
|
# @return [Nil] it failed to parse or the arguments are missing
|
25
|
-
def
|
24
|
+
def inquire(mhead, mbody)
|
26
25
|
return nil unless mhead['subject'].start_with?('Undeliverable message')
|
27
26
|
|
28
27
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
29
|
-
|
30
|
-
bodyslices =
|
28
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
29
|
+
bodyslices = emailparts[0].split("\n")
|
31
30
|
readcursor = 0 # (Integer) Points the current cursor position
|
32
31
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
33
32
|
characters = '' # (String) Character set name of the bounce mail
|
@@ -35,15 +34,14 @@ module Sisimai::Lhost
|
|
35
34
|
encodedmsg = ''
|
36
35
|
v = nil
|
37
36
|
|
38
|
-
if
|
39
|
-
# Get character set name
|
40
|
-
|
41
|
-
characters = cv[1].downcase
|
37
|
+
if mhead['content-type'].include?('charset=')
|
38
|
+
# Get character set name, Content-Type: text/plain; charset=ISO-2022-JP
|
39
|
+
characters = mhead['content-type'][mhead['content-type'].index('charset=') + 8, mhead['content-type'].size].downcase
|
42
40
|
end
|
43
41
|
|
44
42
|
while e = bodyslices.shift do
|
45
|
-
# Read error messages and delivery status lines from the head of the email
|
46
|
-
#
|
43
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
44
|
+
# line of the beginning of the original message.
|
47
45
|
if readcursor == 0
|
48
46
|
# Beginning of the bounce message or delivery status part
|
49
47
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -58,7 +56,7 @@ module Sisimai::Lhost
|
|
58
56
|
#
|
59
57
|
# ------- Returned Message --------
|
60
58
|
v = dscontents[-1]
|
61
|
-
if e
|
59
|
+
if e.include?('@') && e.index(' ').nil?
|
62
60
|
# kijitora@notes.example.jp
|
63
61
|
if v['recipient']
|
64
62
|
# There are multiple recipient addresses in the message body.
|
@@ -97,8 +95,10 @@ module Sisimai::Lhost
|
|
97
95
|
|
98
96
|
unless recipients > 0
|
99
97
|
# Fallback: Get the recpient address from RFC822 part
|
100
|
-
|
101
|
-
|
98
|
+
p1 = emailparts[1].index("\nTo: ") || -1
|
99
|
+
p2 = emailparts[1].index("\n", p1 + 6) || -1
|
100
|
+
if p1 > 0
|
101
|
+
v['recipient'] = Sisimai::Address.s3s4(emailparts[1][p1 + 5, p2 - p1 - 5]) || ''
|
102
102
|
recipients += 1 unless v['recipient'].empty?
|
103
103
|
end
|
104
104
|
end
|
@@ -117,7 +117,7 @@ module Sisimai::Lhost
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
120
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
121
121
|
end
|
122
122
|
def description; return 'Lotus Notes'; end
|
123
123
|
end
|
@@ -1,25 +1,44 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Office365 parses a bounce email which created by
|
3
|
-
#
|
4
|
-
# Methods in the module are called from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::Office365 parses a bounce email which created by Microsoft Office 365. Methods in
|
3
|
+
# the module are called from only Sisimai::Message.
|
5
4
|
module Office365
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Office365.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822', 'Original message headers:'].freeze
|
12
10
|
StartingOf = {
|
13
11
|
error: ['Diagnostic information for administrators:'],
|
14
12
|
eoerr: ['Original message headers:'],
|
15
13
|
}.freeze
|
16
14
|
MarkingsOf = {
|
17
|
-
eoe: %r
|
18
|
-
|
15
|
+
eoe: %r{\A(?:
|
16
|
+
Original[ ][Mm]essage[ ][Hh]eaders:?
|
17
|
+
|Message[ ]Hops
|
18
|
+
|Cabe.+alhos[ ]originais[ ]da[ ]mensagem:
|
19
|
+
|Oorspronkelijke[ ]berichtkoppen:
|
20
|
+
)
|
21
|
+
}x,
|
22
|
+
rfc3464: %r|\AContent-Type:[ ]message/delivery-status|,
|
23
|
+
lhost: %r{\A(?:
|
24
|
+
Generating[ ]server
|
25
|
+
|Bronserver
|
26
|
+
|Servidor[ ]de[ ]origem
|
27
|
+
):[ ](.+)\z
|
28
|
+
}x,
|
29
|
+
error: %r{\A(?:
|
30
|
+
Diagnostic[ ]information[ ]for[ ]administrators:
|
31
|
+
|Error[ ]Details
|
32
|
+
|Diagnostische[ ]gegevens[ ]voor[ ]beheerders:
|
33
|
+
|Informa.+es[ ]de[ ]diagn.+stico[ ]para[ ]administradores:
|
34
|
+
)
|
35
|
+
}x,
|
19
36
|
message: %r{\A(?:
|
20
37
|
Delivery[ ]has[ ]failed[ ]to[ ]these[ ]recipients[ ]or[ ]groups:
|
21
38
|
|Original[ ]Message[ ]Details
|
22
39
|
|.+[ ]rejected[ ]your[ ]message[ ]to[ ]the[ ]following[ ]e[-]?mail[ ]addresses:
|
40
|
+
|Falha[ ]na[ ]entrega[ ]a[ ]estes[ ]destinat.+rios[ ]ou[ ]grupos:
|
41
|
+
|Uw[ ]bericht[ ]kan[ ]niet[ ]worden[ ]bezorgd[ ]bij[ ]de[ ]volgende[ ]geadresseerden[ ]of[ ]groepen:
|
23
42
|
)
|
24
43
|
}x,
|
25
44
|
}.freeze
|
@@ -37,7 +56,7 @@ module Sisimai::Lhost
|
|
37
56
|
%r/\A4[.]4[.]7\z/ => 'expired',
|
38
57
|
%r/\A4[.]4[.]312\z/ => 'networkerror',
|
39
58
|
%r/\A4[.]4[.]316\z/ => 'expired',
|
40
|
-
%r/\A4[.]7[.]26\z/ => '
|
59
|
+
%r/\A4[.]7[.]26\z/ => 'authfailure',
|
41
60
|
%r/\A4[.]7[.][56]\d\d\z/ => 'blocked',
|
42
61
|
%r/\A4[.]7[.]8[5-9]\d\z/ => 'blocked',
|
43
62
|
%r/\A5[.]0[.]350\z/ => 'contenterror',
|
@@ -57,10 +76,10 @@ module Sisimai::Lhost
|
|
57
76
|
%r/\A5[.]7[.]50[4-5]\z/ => 'filtered',
|
58
77
|
%r/\A5[.]7[.]50[6-7]\z/ => 'blocked',
|
59
78
|
%r/\A5[.]7[.]508\z/ => 'toomanyconn',
|
60
|
-
%r/\A5[.]7[.]509\z/ => '
|
79
|
+
%r/\A5[.]7[.]509\z/ => 'authfailure',
|
61
80
|
%r/\A5[.]7[.]510\z/ => 'notaccept',
|
62
81
|
%r/\A5[.]7[.]511\z/ => 'rejected',
|
63
|
-
%r/\A5[.]7[.]512\z/ => '
|
82
|
+
%r/\A5[.]7[.]512\z/ => 'authfailure',
|
64
83
|
%r/\A5[.]7[.]57\z/ => 'securityerror',
|
65
84
|
%r/\A5[.]7[.]60[6-9]\z/ => 'blocked',
|
66
85
|
%r/\A5[.]7[.]6[1-4]\d\z/ => 'blocked',
|
@@ -75,7 +94,7 @@ module Sisimai::Lhost
|
|
75
94
|
# @param [String] mbody Message body of a bounce email
|
76
95
|
# @return [Hash] Bounce data list and message/rfc822 part
|
77
96
|
# @return [Nil] it failed to parse or the arguments are missing
|
78
|
-
def
|
97
|
+
def inquire(mhead, mbody)
|
79
98
|
# X-MS-Exchange-Message-Is-Ndr:
|
80
99
|
# X-Microsoft-Antispam-PRVS: <....@...outlook.com>
|
81
100
|
# X-Exchange-Antispam-Report-Test: UriScan:;
|
@@ -86,6 +105,9 @@ module Sisimai::Lhost
|
|
86
105
|
tryto = %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/
|
87
106
|
match = 0
|
88
107
|
match += 1 if mhead['subject'].include?('Undeliverable:')
|
108
|
+
match += 1 if mhead['subject'].include?('Onbestelbaar:')
|
109
|
+
match += 1 if mhead['subject'].include?('Não_entregue:')
|
110
|
+
|
89
111
|
Headers365.each do |e|
|
90
112
|
next if mhead[e].nil?
|
91
113
|
next if mhead[e].empty?
|
@@ -102,8 +124,8 @@ module Sisimai::Lhost
|
|
102
124
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
103
125
|
permessage = {} # (Hash) Store values of each Per-Message field
|
104
126
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
105
|
-
|
106
|
-
bodyslices =
|
127
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
128
|
+
bodyslices = emailparts[0].split("\n")
|
107
129
|
readcursor = 0 # (Integer) Points the current cursor position
|
108
130
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
109
131
|
connheader = {}
|
@@ -112,8 +134,8 @@ module Sisimai::Lhost
|
|
112
134
|
v = nil
|
113
135
|
|
114
136
|
while e = bodyslices.shift do
|
115
|
-
# Read error messages and delivery status lines from the head of the email
|
116
|
-
#
|
137
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
138
|
+
# line of the beginning of the original message.
|
117
139
|
if readcursor == 0
|
118
140
|
# Beginning of the bounce message or delivery status part
|
119
141
|
readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
|
@@ -145,7 +167,7 @@ module Sisimai::Lhost
|
|
145
167
|
v['recipient'] = cv[1]
|
146
168
|
recipients += 1
|
147
169
|
|
148
|
-
elsif cv = e.match(
|
170
|
+
elsif cv = e.match(MarkingsOf[:lhost])
|
149
171
|
# Generating server: FFFFFFFFFFFF.e0.prod.outlook.com
|
150
172
|
connheader['lhost'] = cv[1].downcase
|
151
173
|
else
|
@@ -154,11 +176,20 @@ module Sisimai::Lhost
|
|
154
176
|
next unless f = Sisimai::RFC1894.match(e)
|
155
177
|
next unless o = Sisimai::RFC1894.field(e)
|
156
178
|
next unless fieldtable[o[0]]
|
157
|
-
next if o[0] =~ /\A(?:diagnostic-code|final-recipient)\z/
|
158
|
-
v[fieldtable[o[0]]] = o[2]
|
159
179
|
|
160
|
-
|
161
|
-
|
180
|
+
if v['diagnosis']
|
181
|
+
# Do not capture "Diagnostic-Code:" field because error message have already
|
182
|
+
# been captured
|
183
|
+
next if o[0] =~ /\A(?:diagnostic-code|final-recipient)\z/
|
184
|
+
v[fieldtable[o[0]]] = o[2]
|
185
|
+
|
186
|
+
next unless f
|
187
|
+
permessage[fieldtable[o[0]]] = o[2]
|
188
|
+
else
|
189
|
+
# Capture "Diagnostic-Code:" field because no error messages have been captured
|
190
|
+
v[fieldtable[o[0]]] = o[2]
|
191
|
+
permessage[fieldtable[o[0]]] = o[2]
|
192
|
+
end
|
162
193
|
else
|
163
194
|
if e =~ MarkingsOf[:error]
|
164
195
|
# Diagnostic information for administrators:
|
@@ -167,13 +198,18 @@ module Sisimai::Lhost
|
|
167
198
|
# kijitora@example.com
|
168
199
|
# Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipien=
|
169
200
|
# t not found by SMTP address lookup'
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
201
|
+
if v['diagnosis']
|
202
|
+
# The error message text have already captured
|
203
|
+
if e =~ MarkingsOf[:eoe]
|
204
|
+
# Original message headers:
|
205
|
+
endoferror = true
|
206
|
+
next
|
207
|
+
end
|
208
|
+
v['diagnosis'] << ' ' << e
|
209
|
+
else
|
210
|
+
# The error message text has not been captured yet
|
211
|
+
endoferror = true if e =~ MarkingsOf[:rfc3464]
|
175
212
|
end
|
176
|
-
v['diagnosis'] << ' ' << e
|
177
213
|
end
|
178
214
|
end
|
179
215
|
end
|
@@ -207,7 +243,7 @@ module Sisimai::Lhost
|
|
207
243
|
end
|
208
244
|
end
|
209
245
|
|
210
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
246
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
211
247
|
end
|
212
248
|
def description; return 'Microsoft Office 365: https://office.microsoft.com/'; end
|
213
249
|
end
|