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,14 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::SurfControl parses a bounce email which created by
|
3
|
-
# WebSense SurfControl.
|
2
|
+
# Sisimai::Lhost::SurfControl parses a bounce email which created by WebSense SurfControl.
|
4
3
|
# Methods in the module are called from only Sisimai::Message.
|
5
4
|
module SurfControl
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/SurfControl.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
12
10
|
StartingOf = { message: ['Your message could not be sent.'] }.freeze
|
13
11
|
|
14
12
|
# Parse bounce messages from SurfControl
|
@@ -16,7 +14,7 @@ module Sisimai::Lhost
|
|
16
14
|
# @param [String] mbody Message body of a bounce email
|
17
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
18
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
19
|
-
def
|
17
|
+
def inquire(mhead, mbody)
|
20
18
|
# X-SEF-ZeroHour-RefID: fgs=000000000
|
21
19
|
# X-SEF-Processed: 0_0_0_000__2010_04_29_23_34_45
|
22
20
|
# X-Mailer: SurfControl E-mail Filter
|
@@ -24,19 +22,18 @@ module Sisimai::Lhost
|
|
24
22
|
return nil unless mhead['x-mailer']
|
25
23
|
return nil unless mhead['x-mailer'] == 'SurfControl E-mail Filter'
|
26
24
|
|
27
|
-
require 'sisimai/rfc1894'
|
28
25
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
29
26
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
30
|
-
|
31
|
-
bodyslices =
|
27
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
28
|
+
bodyslices = emailparts[0].split("\n")
|
32
29
|
readslices = ['']
|
33
30
|
readcursor = 0 # (Integer) Points the current cursor position
|
34
31
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
35
32
|
v = nil
|
36
33
|
|
37
34
|
while e = bodyslices.shift do
|
38
|
-
# Read error messages and delivery status lines from the head of the email
|
39
|
-
#
|
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.
|
40
37
|
readslices << e # Save the current line for the next loop
|
41
38
|
|
42
39
|
if readcursor == 0
|
@@ -58,24 +55,27 @@ module Sisimai::Lhost
|
|
58
55
|
# --- Message non-deliverable.
|
59
56
|
v = dscontents[-1]
|
60
57
|
|
61
|
-
if
|
58
|
+
if e.start_with?('Addressed To:') && e.index('@') > 1
|
62
59
|
# Addressed To: kijitora@example.com
|
63
60
|
if v['recipient']
|
64
61
|
# There are multiple recipient addresses in the message body.
|
65
62
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
66
63
|
v = dscontents[-1]
|
67
64
|
end
|
68
|
-
v['recipient'] =
|
65
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.index(':') + 2, e.size])
|
69
66
|
recipients += 1
|
70
67
|
|
71
|
-
elsif
|
68
|
+
elsif %w[Sun Mon Tue Wed Thu Fri Sat].any? { |a| e.start_with?(a) }
|
72
69
|
# Thu 29 Apr 2010 23:34:45 +0900
|
73
70
|
v['date'] = e
|
74
71
|
|
75
|
-
elsif
|
72
|
+
elsif Sisimai::String.aligned(e, ['@', ':', ' ', '[', '],', '...'])
|
76
73
|
# kijitora@example.com: [192.0.2.5], 550 kijitora@example.com... No such user
|
77
|
-
|
78
|
-
|
74
|
+
p1 = e.index('[')
|
75
|
+
p2 = e.index('],', p1 + 1)
|
76
|
+
v['rhost'] = e[p1 + 1, p2 - p1 - 1]
|
77
|
+
v['diagnosis'] = Sisimai::String.sweep(e[p2 + 2, e.size])
|
78
|
+
|
79
79
|
else
|
80
80
|
# Fallback, parse RFC3464 headers.
|
81
81
|
if f = Sisimai::RFC1894.match(e)
|
@@ -87,8 +87,8 @@ module Sisimai::Lhost
|
|
87
87
|
else
|
88
88
|
# Continued line of the value of Diagnostic-Code field
|
89
89
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
90
|
-
next unless
|
91
|
-
v['diagnosis'] << ' ' <<
|
90
|
+
next unless e.start_with?(' ')
|
91
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
92
92
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
93
93
|
end
|
94
94
|
end
|
@@ -96,7 +96,7 @@ module Sisimai::Lhost
|
|
96
96
|
return nil unless recipients > 0
|
97
97
|
|
98
98
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
99
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
99
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
100
100
|
end
|
101
101
|
def description; return 'WebSense SurfControl'; end
|
102
102
|
end
|
@@ -1,16 +1,13 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::V5sendmail parses a bounce email which created by
|
3
|
-
#
|
4
|
-
# Methods in the module are called from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::V5sendmail parses a bounce email which created by Sendmail version 5. Methods in
|
3
|
+
# the module are called from only Sisimai::Message.
|
5
4
|
module V5sendmail
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/V5sendmail.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
12
|
-
StartingOf = {
|
13
|
-
MarkingsOf = {
|
9
|
+
Boundaries = [' ----- Unsent message follows -----', ' ----- No message was collected -----'].freeze
|
10
|
+
StartingOf = {
|
14
11
|
# Error text regular expressions which defined in src/savemail.c
|
15
12
|
# savemail.c:485| (void) fflush(stdout);
|
16
13
|
# savemail.c:486| p = queuename(e->e_parent, 'x');
|
@@ -27,7 +24,8 @@ module Sisimai::Lhost
|
|
27
24
|
# savemail.c:497| while (fgets(buf, sizeof buf, xfile) != NULL)
|
28
25
|
# savemail.c:498| putline(buf, fp, m);
|
29
26
|
# savemail.c:499| (void) fclose(xfile);
|
30
|
-
error:
|
27
|
+
error: [' while talking to '],
|
28
|
+
message: ['----- Transcript of session follows -----'],
|
31
29
|
}.freeze
|
32
30
|
|
33
31
|
# Parse bounce messages from Sendmail version 5
|
@@ -35,26 +33,27 @@ module Sisimai::Lhost
|
|
35
33
|
# @param [String] mbody Message body of a bounce email
|
36
34
|
# @return [Hash] Bounce data list and message/rfc822 part
|
37
35
|
# @return [Nil] it failed to parse or the arguments are missing
|
38
|
-
def
|
36
|
+
def inquire(mhead, mbody)
|
39
37
|
# :from => %r/\AMail Delivery Subsystem/,
|
40
|
-
return nil unless mhead['subject']
|
38
|
+
return nil unless mhead['subject'].start_with?('Returned mail: ')
|
41
39
|
|
42
|
-
|
43
|
-
return nil
|
40
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
41
|
+
return nil unless emailparts[1].size > 0
|
44
42
|
|
43
|
+
require 'sisimai/smtp/command'
|
45
44
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
46
|
-
bodyslices =
|
45
|
+
bodyslices = emailparts[0].split("\n")
|
47
46
|
readcursor = 0 # (Integer) Points the current cursor position
|
48
47
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
48
|
+
anotherset = {} # (Hash) Another error information
|
49
49
|
responding = [] # (Array) Responses from remote server
|
50
50
|
commandset = [] # (Array) SMTP command which is sent to remote server
|
51
|
-
anotherset = {} # (Hash) Another error information
|
52
51
|
errorindex = -1 # (Integer)
|
53
52
|
v = nil
|
54
53
|
|
55
54
|
while e = bodyslices.shift do
|
56
|
-
# Read error messages and delivery status lines from the head of the email
|
57
|
-
#
|
55
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
56
|
+
# line of the beginning of the original message.
|
58
57
|
if readcursor == 0
|
59
58
|
# Beginning of the bounce message or delivery status part
|
60
59
|
readcursor |= Indicators[:deliverystatus] if e.include?(StartingOf[:message][0])
|
@@ -71,57 +70,64 @@ module Sisimai::Lhost
|
|
71
70
|
# 421 example.org (smtp)... Deferred: Connection timed out during user open with example.org
|
72
71
|
v = dscontents[-1]
|
73
72
|
|
74
|
-
if
|
73
|
+
if e.start_with?('5', '4') && Sisimai::String.aligned(e, [' <', '@', '>...'])
|
75
74
|
# 550 <kijitora@example.org>... User unknown
|
76
75
|
if v['recipient']
|
77
76
|
# There are multiple recipient addresses in the message body.
|
78
77
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
79
78
|
v = dscontents[-1]
|
80
79
|
end
|
81
|
-
|
82
|
-
|
80
|
+
p1 = e.index('<', 0)
|
81
|
+
p2 = e.index('>...')
|
82
|
+
v['recipient'] = e[p1 + 1, p2 - p1 - 1]
|
83
|
+
v['diagnosis'] = e[p2 + 5, e.size]
|
83
84
|
|
84
85
|
# Concatenate the response of the server and error message
|
85
86
|
v['diagnosis'] << ': ' << responding[recipients] if responding[recipients]
|
86
87
|
recipients += 1
|
87
88
|
|
88
|
-
elsif
|
89
|
+
elsif e.start_with?('>>> ')
|
89
90
|
# >>> RCPT To:<kijitora@example.org>
|
90
|
-
commandset[recipients] = cv
|
91
|
+
cv = Sisimai::SMTP::Command.find(e); commandset[recipients] = cv if cv
|
91
92
|
|
92
|
-
elsif
|
93
|
+
elsif e.start_with?('<<< ')
|
93
94
|
# <<< Response
|
94
95
|
# <<< 501 <shironeko@example.co.jp>... no access from mail server [192.0.2.55] which is an open relay.
|
95
96
|
# <<< 550 Requested User Mailbox not found. No such user here.
|
96
|
-
responding[recipients] =
|
97
|
+
responding[recipients] = e[4, e.size]
|
98
|
+
|
97
99
|
else
|
98
100
|
# Detect SMTP session error or connection error
|
99
101
|
next if v['sessionerr']
|
100
102
|
|
101
|
-
if e
|
103
|
+
if e.include?(StartingOf[:error][0])
|
102
104
|
# ----- Transcript of session follows -----
|
103
105
|
# ... while talking to mta.example.org.:
|
104
106
|
v['sessionerr'] = true
|
105
107
|
next
|
106
108
|
end
|
107
109
|
|
108
|
-
if
|
110
|
+
if e.start_with?('4', '5') && e.include?('... ')
|
109
111
|
# 421 example.org (smtp)... Deferred: Connection timed out during user open with example.org
|
110
|
-
anotherset['
|
112
|
+
anotherset['replycode'] = e[0, 3]
|
113
|
+
anotherset['diagnosis'] = e[e.index('... ') + 4, e.size]
|
111
114
|
end
|
112
115
|
end
|
113
116
|
end
|
114
117
|
|
115
|
-
|
118
|
+
p1 = emailparts[1].index("\nTo: ") || -1
|
119
|
+
p2 = emailparts[1].index("\n", p1 + 6) || -1
|
120
|
+
if recipients == 0 && p1 > 0
|
116
121
|
# Get the recipient address from "To:" header at the original message
|
117
|
-
dscontents[0]['recipient'] = Sisimai::Address.s3s4(
|
122
|
+
dscontents[0]['recipient'] = Sisimai::Address.s3s4(emailparts[1][p1, p2 - p1 - 5])
|
118
123
|
recipients = 1
|
119
124
|
end
|
120
125
|
return nil unless recipients > 0
|
121
126
|
|
122
127
|
dscontents.each do |e|
|
123
128
|
errorindex += 1
|
124
|
-
e
|
129
|
+
e.delete('sessionerr')
|
130
|
+
|
125
131
|
e['diagnosis'] ||= if anotherset['diagnosis'].to_s.size > 0
|
126
132
|
# Copy alternative error message
|
127
133
|
anotherset['diagnosis']
|
@@ -130,18 +136,18 @@ module Sisimai::Lhost
|
|
130
136
|
responding[errorindex]
|
131
137
|
end
|
132
138
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
e.
|
139
|
+
e['replycode'] = Sisimai::SMTP::Reply.find(e['diagnosis']) || anotherset['replycode']
|
140
|
+
e['command'] = commandset[errorindex] || Sisimai::SMTP::Command.find(e['diagnosis']) || ''
|
141
|
+
|
142
|
+
# @example.jp, no local part
|
143
|
+
# Get email address from the value of Diagnostic-Code header
|
144
|
+
next if e['recipient'].include?('@')
|
145
|
+
p1 = e['diagnosis'].index('<'); next unless p1
|
146
|
+
p2 = e['diagnosis'].index('>'); next unless p2
|
147
|
+
e['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
|
142
148
|
end
|
143
149
|
|
144
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
150
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
145
151
|
end
|
146
152
|
def description; return 'Sendmail version 5'; end
|
147
153
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Verizon parses a bounce email which created by
|
3
|
-
#
|
4
|
-
# Methods in the module are called from only Sisimai::Message.
|
2
|
+
# Sisimai::Lhost::Verizon parses a bounce email which created by Verizon Wireless. Methods in the
|
3
|
+
# module are called from only Sisimai::Message.
|
5
4
|
module Verizon
|
6
5
|
class << self
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Verizon.pm
|
8
6
|
require 'sisimai/lhost'
|
9
7
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
8
|
|
@@ -13,25 +11,25 @@ module Sisimai::Lhost
|
|
13
11
|
# @param [String] mbody Message body of a bounce email
|
14
12
|
# @return [Hash] Bounce data list and message/rfc822 part
|
15
13
|
# @return [Nil] it failed to parse or the arguments are missing
|
16
|
-
def
|
14
|
+
def inquire(mhead, mbody)
|
17
15
|
match = -1
|
18
16
|
while true
|
19
17
|
# Check the value of "From" header
|
20
18
|
# :'subject' => %r/Undeliverable Message/,
|
21
19
|
break unless mhead['received'].any? { |a| a.include?('.vtext.com (') }
|
22
20
|
match = 1 if mhead['from'] == 'post_master@vtext.com'
|
23
|
-
match = 0 if mhead['from']
|
21
|
+
match = 0 if Sisimai::String.aligned(mhead['from'], ['sysadmin@', '.vzwpix.com'])
|
24
22
|
break
|
25
23
|
end
|
26
24
|
return nil if match < 0
|
27
25
|
|
26
|
+
boundaries = []
|
28
27
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
29
|
-
|
28
|
+
emailparts = []
|
30
29
|
readcursor = 0 # (Integer) Points the current cursor position
|
31
30
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
32
31
|
senderaddr = '' # (String) Sender address in the message body
|
33
32
|
subjecttxt = '' # (String) Subject of the original message
|
34
|
-
|
35
33
|
markingsof = {} # (Hash) Delimiter patterns
|
36
34
|
startingof = {} # (Hash) Delimiter strings
|
37
35
|
messagesof = {} # (Hash) Error message patterns
|
@@ -39,22 +37,21 @@ module Sisimai::Lhost
|
|
39
37
|
|
40
38
|
if match == 1
|
41
39
|
# vtext.com
|
42
|
-
markingsof = { message:
|
40
|
+
markingsof = { message: ['Error: '] }
|
43
41
|
messagesof = {
|
44
42
|
# The attempted recipient address does not exist.
|
45
43
|
'userunknown' => ['550 - Requested action not taken: no such user here'],
|
46
44
|
}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
bodyslices = emailsteak[0].split("\n")
|
45
|
+
boundaries = [Sisimai::RFC2045.boundary(mhead['content-type'], 1)]
|
46
|
+
emailparts = Sisimai::RFC5322.part(mbody, boundaries)
|
47
|
+
bodyslices = emailparts[0].split("\n")
|
51
48
|
|
52
49
|
while e = bodyslices.shift do
|
53
|
-
# Read error messages and delivery status lines from the head of the email
|
54
|
-
#
|
50
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
51
|
+
# line of the beginning of the original message.
|
55
52
|
if readcursor == 0
|
56
53
|
# Beginning of the bounce message or delivery status part
|
57
|
-
readcursor |= Indicators[:deliverystatus] if e
|
54
|
+
readcursor |= Indicators[:deliverystatus] if e.start_with?(markingsof[:message][0])
|
58
55
|
next
|
59
56
|
end
|
60
57
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
@@ -66,41 +63,40 @@ module Sisimai::Lhost
|
|
66
63
|
# MAIL FROM: *******@hg.example.com
|
67
64
|
# RCPT TO: *****@vtext.com
|
68
65
|
v = dscontents[-1]
|
69
|
-
if
|
66
|
+
if e.start_with?(' RCPT TO: ')
|
70
67
|
if v['recipient']
|
71
68
|
# There are multiple recipient addresses in the message body.
|
72
69
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
73
70
|
v = dscontents[-1]
|
74
71
|
end
|
75
72
|
|
76
|
-
v['recipient'] =
|
73
|
+
v['recipient'] = e[11, e.size]
|
77
74
|
recipients += 1
|
78
75
|
next
|
79
76
|
|
80
|
-
elsif
|
77
|
+
elsif e.start_with?(' MAIL FROM: ')
|
81
78
|
# MAIL FROM: *******@hg.example.com
|
82
|
-
senderaddr =
|
79
|
+
senderaddr = e[13, e.size] if senderaddr.empty?
|
83
80
|
|
84
|
-
elsif
|
81
|
+
elsif e.start_with?(' Subject: ')
|
85
82
|
# Subject:
|
86
|
-
subjecttxt =
|
83
|
+
subjecttxt = e[11, e.size] if subjecttxt.empty?
|
87
84
|
else
|
88
85
|
# 550 - Requested action not taken: no such user here
|
89
|
-
v['diagnosis'] = e if e
|
86
|
+
v['diagnosis'] = e if e.include?(' - ')
|
90
87
|
end
|
91
88
|
end
|
92
89
|
else
|
93
90
|
# vzwpix.com
|
94
91
|
startingof = { message: ['Message could not be delivered to mobile'] }
|
95
92
|
messagesof = { 'userunknown' => ['No valid recipients for this MM'] }
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
bodyslices = emailsteak[0].split("\n")
|
93
|
+
boundaries = [Sisimai::RFC2045.boundary(mhead['content-type'], 1)]
|
94
|
+
emailparts = Sisimai::RFC5322.part(mbody, boundaries)
|
95
|
+
bodyslices = emailparts[0].split("\n")
|
100
96
|
|
101
97
|
while e = bodyslices.shift do
|
102
|
-
# Read error messages and delivery status lines from the head of the email
|
103
|
-
#
|
98
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
99
|
+
# line of the beginning of the original message.
|
104
100
|
if readcursor == 0
|
105
101
|
# Beginning of the bounce message or delivery status part
|
106
102
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(startingof[:message][0])
|
@@ -115,35 +111,35 @@ module Sisimai::Lhost
|
|
115
111
|
# Subject: test for bounce
|
116
112
|
# Date: Wed, 20 Jun 2013 10:29:52 +0000
|
117
113
|
v = dscontents[-1]
|
118
|
-
if
|
114
|
+
if e.start_with?('To: ')
|
119
115
|
if v['recipient']
|
120
116
|
# There are multiple recipient addresses in the message body.
|
121
117
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
122
118
|
v = dscontents[-1]
|
123
119
|
end
|
124
|
-
v['recipient'] = Sisimai::Address.s3s4(
|
120
|
+
v['recipient'] = Sisimai::Address.s3s4(e[4, e.size])
|
125
121
|
recipients += 1
|
126
122
|
next
|
127
123
|
|
128
|
-
elsif
|
124
|
+
elsif e.start_with?('From: ')
|
129
125
|
# From: kijitora <kijitora@example.jp>
|
130
|
-
senderaddr = Sisimai::Address.s3s4(
|
126
|
+
senderaddr = Sisimai::Address.s3s4(e[4, e.size]) if senderaddr.empty?
|
131
127
|
|
132
|
-
elsif
|
128
|
+
elsif e.start_with?('Subject: ')
|
133
129
|
# Subject:
|
134
|
-
subjecttxt =
|
130
|
+
subjecttxt = e[9, e.size] if subjecttxt.empty?
|
135
131
|
else
|
136
132
|
# Message could not be delivered to mobile.
|
137
133
|
# Error: No valid recipients for this MM
|
138
|
-
v['diagnosis'] = e if e
|
134
|
+
v['diagnosis'] = Sisimai::String.sweep(e[7, e.size]) if e.start_with?('Error: ')
|
139
135
|
end
|
140
136
|
end
|
141
137
|
end
|
142
138
|
return nil unless recipients > 0
|
143
139
|
|
144
140
|
# Set the value of "MAIL FROM:" and "From:"
|
145
|
-
|
146
|
-
|
141
|
+
emailparts[1] << ('From: ' << senderaddr << "\n") if emailparts[1].include?("\nFrom: ") == false
|
142
|
+
emailparts[1] << ('Subject: ' << subjecttxt << "\n") if emailparts[1].include?("\nSubject: ") == false
|
147
143
|
|
148
144
|
dscontents.each do |e|
|
149
145
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
@@ -155,7 +151,7 @@ module Sisimai::Lhost
|
|
155
151
|
end
|
156
152
|
end
|
157
153
|
|
158
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
154
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
159
155
|
end
|
160
156
|
def description; return 'Verizon Wireless: https://www.verizonwireless.com'; end
|
161
157
|
end
|
data/lib/sisimai/lhost/x1.rb
CHANGED
@@ -1,38 +1,37 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::X1 parses a bounce email which created by Unknown MTA #1.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::X1 parses a bounce email which created by Unknown MTA #1. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module X1
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/X1.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
11
|
-
MarkingsOf = { message:
|
9
|
+
Boundaries = ['Received: from '].freeze
|
10
|
+
MarkingsOf = { message: ['The original message was received at '] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Unknown MTA #1
|
14
13
|
# @param [Hash] mhead Message headers of a bounce email
|
15
14
|
# @param [String] mbody Message body of a bounce email
|
16
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
17
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
18
|
-
def
|
17
|
+
def inquire(mhead, mbody)
|
19
18
|
return nil unless mhead['subject'].start_with?('Returned Mail: ')
|
20
19
|
return nil unless mhead['from'].start_with?('"Mail Deliver System" ')
|
21
20
|
|
22
21
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
23
|
-
|
24
|
-
bodyslices =
|
22
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
23
|
+
bodyslices = emailparts[0].split("\n")
|
25
24
|
readcursor = 0 # (Integer) Points the current cursor position
|
26
25
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
27
26
|
datestring = '' # (String) Date string
|
28
27
|
v = nil
|
29
28
|
|
30
29
|
while e = bodyslices.shift do
|
31
|
-
# Read error messages and delivery status lines from the head of the email
|
32
|
-
#
|
30
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
31
|
+
# line of the beginning of the original message.
|
33
32
|
if readcursor == 0
|
34
33
|
# Beginning of the bounce message or delivery status part
|
35
|
-
readcursor |= Indicators[:deliverystatus] if e
|
34
|
+
readcursor |= Indicators[:deliverystatus] if e.start_with?(MarkingsOf[:message][0])
|
36
35
|
next
|
37
36
|
end
|
38
37
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
@@ -46,20 +45,22 @@ module Sisimai::Lhost
|
|
46
45
|
# kijitora@example.co.jp [User unknown]
|
47
46
|
v = dscontents[-1]
|
48
47
|
|
49
|
-
if
|
48
|
+
if Sisimai::String.aligned(e, ['@', ' [', ']'])
|
50
49
|
# kijitora@example.co.jp [User unknown]
|
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
|
-
|
57
|
-
|
55
|
+
p1 = e.index(' ')
|
56
|
+
p2 = e.index(']')
|
57
|
+
v['recipient'] = e[0, p1]
|
58
|
+
v['diagnosis'] = e[p1 + 2, p2 - p1 - 2]
|
58
59
|
recipients += 1
|
59
60
|
|
60
|
-
elsif
|
61
|
+
elsif e.start_with?(MarkingsOf[:message][0])
|
61
62
|
# The original message was received at Thu, 29 Apr 2010 23:34:45 +0900 (JST)
|
62
|
-
datestring =
|
63
|
+
datestring = e[MarkingsOf[:message][0].size, e.size]
|
63
64
|
end
|
64
65
|
end
|
65
66
|
return nil unless recipients > 0
|
@@ -69,7 +70,7 @@ module Sisimai::Lhost
|
|
69
70
|
e['date'] = datestring || ''
|
70
71
|
end
|
71
72
|
|
72
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
73
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
73
74
|
end
|
74
75
|
def description; return 'Unknown MTA #1'; end
|
75
76
|
end
|
data/lib/sisimai/lhost/x2.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::X2 parses a bounce email which created by Unknown MTA #2.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::X2 parses a bounce email which created by Unknown MTA #2. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module X2
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/X2.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['--- Original message follows.'].freeze
|
11
10
|
StartingOf = { message: ['Unable to deliver message to the following address'] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Unknown MTA #2
|
@@ -15,20 +14,24 @@ module Sisimai::Lhost
|
|
15
14
|
# @param [String] mbody Message body of a bounce email
|
16
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
17
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
18
|
-
def
|
19
|
-
|
20
|
-
|
17
|
+
def inquire(mhead, mbody)
|
18
|
+
match = nil
|
19
|
+
match ||= 1 if mhead['from'].include?('MAILER-DAEMON@')
|
20
|
+
match ||= 1 if mhead['subject'].start_with?('Delivery failure')
|
21
|
+
match ||= 1 if mhead['subject'].start_with?('failure delivery')
|
22
|
+
match ||= 1 if mhead['subject'].start_with?('failed delivery')
|
23
|
+
return nil unless match
|
21
24
|
|
22
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
23
|
-
|
24
|
-
bodyslices =
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
25
28
|
readcursor = 0 # (Integer) Points the current cursor position
|
26
29
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
27
30
|
v = nil
|
28
31
|
|
29
32
|
while e = bodyslices.shift do
|
30
|
-
# Read error messages and delivery status lines from the head of the email
|
31
|
-
#
|
33
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
34
|
+
# line of the beginning of the original message.
|
32
35
|
if readcursor == 0
|
33
36
|
# Beginning of the bounce message or delivery status part
|
34
37
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -44,14 +47,14 @@ module Sisimai::Lhost
|
|
44
47
|
# This user doesn't have a example.com account (kijitora@example.com) [0]
|
45
48
|
v = dscontents[-1]
|
46
49
|
|
47
|
-
if
|
50
|
+
if e.start_with?('<') && Sisimai::String.aligned(e, ['<', '@', '>', ':'])
|
48
51
|
# <kijitora@example.com>:
|
49
52
|
if v['recipient']
|
50
53
|
# There are multiple recipient addresses in the message body.
|
51
54
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
52
55
|
v = dscontents[-1]
|
53
56
|
end
|
54
|
-
v['recipient'] =
|
57
|
+
v['recipient'] = e[1, e.size - 3]
|
55
58
|
recipients += 1
|
56
59
|
else
|
57
60
|
# This user doesn't have a example.com account (kijitora@example.com) [0]
|
@@ -62,7 +65,7 @@ module Sisimai::Lhost
|
|
62
65
|
return nil unless recipients > 0
|
63
66
|
|
64
67
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
65
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
68
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
66
69
|
end
|
67
70
|
def description; return 'Unknown MTA #2'; end
|
68
71
|
end
|