sisimai 4.25.16 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +412 -393
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +140 -78
- data/README.md +290 -143
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +23 -18
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -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/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +12 -12
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +41 -20
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
@@ -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
|