sisimai 4.25.15 → 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 +419 -388
- 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 -313
- 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 -47
- 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,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Barracuda parses a bounce email which created by Barracuda.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Barracuda parses a bounce email which created by Barracuda. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Barracuda
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Barracuda.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
11
10
|
StartingOf = { message: ['Your message to:'] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Barracuda
|
@@ -16,24 +15,23 @@ module Sisimai::Lhost
|
|
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
17
|
# @since v4.25.6
|
19
|
-
def
|
18
|
+
def inquire(mhead, mbody)
|
20
19
|
# Subject: **Message you sent blocked by our bulk email filter**
|
21
20
|
return nil unless mhead['subject'].to_s.end_with?('our bulk email filter**')
|
22
21
|
|
23
|
-
require 'sisimai/rfc1894'
|
24
22
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
25
23
|
permessage = {} # (Hash) Store values of each Per-Message field
|
26
24
|
|
27
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
28
|
-
|
29
|
-
bodyslices =
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
30
28
|
readcursor = 0 # (Integer) Points the current cursor position
|
31
29
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
32
30
|
v = nil
|
33
31
|
|
34
32
|
while e = bodyslices.shift do
|
35
|
-
# Read error messages and delivery status lines from the head of the email
|
36
|
-
#
|
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.
|
37
35
|
if readcursor == 0
|
38
36
|
# Beginning of the bounce message or message/delivery-status part
|
39
37
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -72,7 +70,7 @@ module Sisimai::Lhost
|
|
72
70
|
next unless fieldtable[o[0]]
|
73
71
|
v[fieldtable[o[0]]] = o[2]
|
74
72
|
|
75
|
-
next unless f
|
73
|
+
next unless f
|
76
74
|
permessage[fieldtable[o[0]]] = o[2]
|
77
75
|
end
|
78
76
|
end
|
@@ -85,7 +83,7 @@ module Sisimai::Lhost
|
|
85
83
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].to_s.tr("\n", ' '))
|
86
84
|
end
|
87
85
|
|
88
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
86
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
89
87
|
end
|
90
88
|
def description; return 'Barracuda: https://www.barracuda.com'; end
|
91
89
|
end
|
@@ -1,49 +1,49 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Bigfoot parses a bounce email which created by Bigfoot.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Bigfoot parses a bounce email which created by Bigfoot. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Bigfoot
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Bigfoot.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
11
|
-
MarkingsOf = { message:
|
9
|
+
Boundaries = ['Content-Type: message/partial'].freeze
|
10
|
+
MarkingsOf = { message: ' ----- Transcript of session follows -----' }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Bigfoot
|
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
|
# :subject => %r/\AReturned mail: /,
|
20
19
|
match = 0
|
21
20
|
match += 1 if mhead['from'].include?('@bigfoot.com>')
|
22
21
|
match += 1 if mhead['received'].any? { |a| a.include?('.bigfoot.com') }
|
23
22
|
return nil unless match > 0
|
24
23
|
|
24
|
+
require 'sisimai/smtp/command'
|
25
25
|
require 'sisimai/rfc1894'
|
26
26
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
27
27
|
permessage = {} # (Hash) Store values of each Per-Message field
|
28
28
|
|
29
29
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
30
|
-
|
31
|
-
bodyslices =
|
30
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
31
|
+
bodyslices = emailparts[0].split("\n")
|
32
32
|
readslices = ['']
|
33
33
|
readcursor = 0 # (Integer) Points the current cursor position
|
34
34
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
35
|
-
|
35
|
+
thecommand = '' # (String) SMTP Command name begin with the string '>>>'
|
36
36
|
esmtpreply = '' # (String) Reply from remote server on SMTP session
|
37
37
|
v = nil
|
38
38
|
|
39
39
|
while e = bodyslices.shift do
|
40
|
-
# Read error messages and delivery status lines from the head of the email
|
41
|
-
#
|
40
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
41
|
+
# line of the beginning of the original message.
|
42
42
|
readslices << e # Save the current line for the next loop
|
43
43
|
|
44
44
|
if readcursor == 0
|
45
45
|
# Beginning of the bounce message or message/delivery-status part
|
46
|
-
readcursor |= Indicators[:deliverystatus] if e
|
46
|
+
readcursor |= Indicators[:deliverystatus] if e.start_with?(MarkingsOf[:message])
|
47
47
|
next
|
48
48
|
end
|
49
49
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
@@ -79,7 +79,7 @@ module Sisimai::Lhost
|
|
79
79
|
next unless fieldtable[o[0]]
|
80
80
|
v[fieldtable[o[0]]] = o[2]
|
81
81
|
|
82
|
-
next unless f
|
82
|
+
next unless f
|
83
83
|
permessage[fieldtable[o[0]]] = o[2]
|
84
84
|
end
|
85
85
|
else
|
@@ -88,18 +88,18 @@ module Sisimai::Lhost
|
|
88
88
|
# ----- Transcript of session follows -----
|
89
89
|
# >>> RCPT TO:<destinaion@example.net>
|
90
90
|
# <<< 553 Invalid recipient destinaion@example.net (Mode: normal)
|
91
|
-
if
|
91
|
+
if e.start_with?('>>> ')
|
92
92
|
# >>> DATA
|
93
|
-
|
94
|
-
elsif
|
93
|
+
thecommand = Sisimai::SMTP::Command.find(e)
|
94
|
+
elsif e.start_with?('<<< ')
|
95
95
|
# <<< Response
|
96
|
-
esmtpreply =
|
96
|
+
esmtpreply = e[4, e.size - 4]
|
97
97
|
end
|
98
98
|
else
|
99
99
|
# Continued line of the value of Diagnostic-Code field
|
100
100
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
101
|
-
next unless
|
102
|
-
v['diagnosis'] << ' ' <<
|
101
|
+
next unless e.start_with?(' ')
|
102
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e[1, e.size])
|
103
103
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
104
104
|
end
|
105
105
|
end
|
@@ -111,13 +111,13 @@ module Sisimai::Lhost
|
|
111
111
|
e['lhost'] ||= permessage['rhost']
|
112
112
|
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
113
113
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
114
|
-
e['command'] =
|
114
|
+
e['command'] = thecommand || ''
|
115
115
|
if e['command'].empty?
|
116
116
|
e['command'] = 'EHLO' unless esmtpreply.empty?
|
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 'Bigfoot: http://www.bigfoot.com'; end
|
123
123
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Biglobe parses a bounce email which created by BIGLOBE.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Biglobe parses a bounce email which created by BIGLOBE. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Biglobe
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Biglobe.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = {
|
12
11
|
message: [' ----- The following addresses had delivery problems -----'],
|
13
12
|
error: [' ----- Non-delivered information -----'],
|
@@ -22,20 +21,21 @@ 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
|
26
|
-
return nil unless mhead['from']
|
24
|
+
def inquire(mhead, mbody)
|
25
|
+
return nil unless mhead['from'].include?('postmaster@')
|
26
|
+
return nil unless %w[biglobe inacatv tmtv ttv].any? { |a| mhead['from'].include?('@' + a + '.ne.jp') }
|
27
27
|
return nil unless mhead['subject'].start_with?('Returned mail:')
|
28
28
|
|
29
29
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
30
|
-
|
31
|
-
bodyslices =
|
30
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
31
|
+
bodyslices = emailparts[0].split("\n")
|
32
32
|
readcursor = 0 # (Integer) Points the current cursor position
|
33
33
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
34
34
|
v = nil
|
35
35
|
|
36
36
|
while e = bodyslices.shift do
|
37
|
-
# Read error messages and delivery status lines from the head of the email
|
38
|
-
#
|
37
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
38
|
+
# line of the beginning of the original message.
|
39
39
|
if readcursor == 0
|
40
40
|
# Beginning of the bounce message or delivery status part
|
41
41
|
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
@@ -60,7 +60,7 @@ module Sisimai::Lhost
|
|
60
60
|
#
|
61
61
|
v = dscontents[-1]
|
62
62
|
|
63
|
-
if
|
63
|
+
if e.include?('@') && e.include?(' ') == false
|
64
64
|
# ----- The following addresses had delivery problems -----
|
65
65
|
# ********@***.biglobe.ne.jp
|
66
66
|
if v['recipient']
|
@@ -69,12 +69,11 @@ module Sisimai::Lhost
|
|
69
69
|
v = dscontents[-1]
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
v['recipient'] = r
|
72
|
+
next unless Sisimai::Address.is_emailaddress(e)
|
73
|
+
v['recipient'] = e
|
75
74
|
recipients += 1
|
76
75
|
else
|
77
|
-
next if e
|
76
|
+
next if e.include?('--')
|
78
77
|
v['diagnosis'] ||= ''
|
79
78
|
v['diagnosis'] << e + ' '
|
80
79
|
end
|
@@ -92,7 +91,7 @@ module Sisimai::Lhost
|
|
92
91
|
end
|
93
92
|
end
|
94
93
|
|
95
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
94
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
96
95
|
end
|
97
96
|
def description; return 'BIGLOBE: https://www.biglobe.ne.jp'; end
|
98
97
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Courier parses a bounce email which created by Courier
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Courier parses a bounce email which created by Courier MTA. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Courier
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Courier.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
# https://www.courier-mta.org/courierdsn.html
|
10
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
10
|
+
Boundaries = ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'].freeze
|
12
11
|
StartingOf = {
|
13
12
|
# courier/module.dsn/dsn*.txt
|
14
13
|
message: ['DELAYS IN DELIVERING YOUR MESSAGE', 'UNDELIVERABLE MAIL'],
|
@@ -29,32 +28,34 @@ module Sisimai::Lhost
|
|
29
28
|
# @param [String] mbody Message body of a bounce email
|
30
29
|
# @return [Hash] Bounce data list and message/rfc822 part
|
31
30
|
# @return [Nil] it failed to parse or the arguments are missing
|
32
|
-
def
|
31
|
+
def inquire(mhead, mbody)
|
33
32
|
match = 0
|
34
33
|
match += 1 if mhead['from'].include?('Courier mail server at ')
|
35
|
-
match += 1 if mhead['subject']
|
34
|
+
match += 1 if mhead['subject'].include?('NOTICE: mail delivery status.')
|
35
|
+
match += 1 if mhead['subject'].include?('WARNING: delayed mail.')
|
36
36
|
if mhead['message-id']
|
37
37
|
# Message-ID: <courier.4D025E3A.00001792@5jo.example.org>
|
38
|
-
match += 1 if mhead['message-id']
|
38
|
+
match += 1 if mhead['message-id'].start_with?('<courier.')
|
39
39
|
end
|
40
40
|
return nil unless match > 0
|
41
41
|
|
42
|
+
require 'sisimai/smtp/command'
|
42
43
|
require 'sisimai/rfc1894'
|
43
44
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
44
45
|
permessage = {} # (Hash) Store values of each Per-Message field
|
45
46
|
|
46
47
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
47
|
-
|
48
|
-
bodyslices =
|
48
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
49
|
+
bodyslices = emailparts[0].split("\n")
|
49
50
|
readslices = ['']
|
50
51
|
readcursor = 0 # (Integer) Points the current cursor position
|
51
52
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
52
|
-
|
53
|
+
thecommand = '' # (String) SMTP Command name begin with the string '>>>'
|
53
54
|
v = nil
|
54
55
|
|
55
56
|
while e = bodyslices.shift do
|
56
|
-
# Read error messages and delivery status lines from the head of the email
|
57
|
-
#
|
57
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
58
|
+
# line of the beginning of the original message.
|
58
59
|
readslices << e # Save the current line for the next loop
|
59
60
|
|
60
61
|
if readcursor == 0
|
@@ -97,12 +98,12 @@ module Sisimai::Lhost
|
|
97
98
|
next unless fieldtable[o[0]]
|
98
99
|
v[fieldtable[o[0]]] = o[2]
|
99
100
|
|
100
|
-
next unless f
|
101
|
+
next unless f
|
101
102
|
permessage[fieldtable[o[0]]] = o[2]
|
102
103
|
end
|
103
104
|
else
|
104
105
|
# The line does not begin with a DSN field defined in RFC3464
|
105
|
-
if
|
106
|
+
if e.start_with?('>>> ')
|
106
107
|
# Your message to the following recipients cannot be delivered:
|
107
108
|
#
|
108
109
|
# <kijitora@example.co.jp>:
|
@@ -110,13 +111,12 @@ module Sisimai::Lhost
|
|
110
111
|
# >>> RCPT TO:<kijitora@example.co.jp>
|
111
112
|
# <<< 550 5.1.1 <kijitora@example.co.jp>... User Unknown
|
112
113
|
#
|
113
|
-
|
114
|
-
commandtxt = cv[1]
|
114
|
+
thecommand = Sisimai::SMTP::Command.find(e)
|
115
115
|
else
|
116
116
|
# Continued line of the value of Diagnostic-Code field
|
117
117
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
118
|
-
next unless
|
119
|
-
v['diagnosis'] << ' ' <<
|
118
|
+
next unless e.start_with?(' ')
|
119
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
120
120
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
121
121
|
end
|
122
122
|
end
|
@@ -126,7 +126,7 @@ module Sisimai::Lhost
|
|
126
126
|
dscontents.each do |e|
|
127
127
|
# Set default values if each value is empty.
|
128
128
|
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
129
|
-
e['command'] ||=
|
129
|
+
e['command'] ||= thecommand || ''
|
130
130
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
131
131
|
|
132
132
|
MessagesOf.each_key do |r|
|
@@ -137,7 +137,7 @@ module Sisimai::Lhost
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
140
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
141
141
|
end
|
142
142
|
def description; return 'Courier MTA'; end
|
143
143
|
end
|
data/lib/sisimai/lhost/domino.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Domino parses a bounce email which created by IBM
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Domino parses a bounce email which created by IBM Domino Server. Methods in the
|
3
|
+
# module are called from only Sisimai::Message.
|
4
4
|
module Domino
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Domino.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = { message: ['Your message'] }.freeze
|
12
11
|
MessagesOf = {
|
13
12
|
'userunknown' => [
|
14
13
|
'not listed in Domino Directory',
|
15
14
|
'not listed in public Name & Address Book',
|
16
|
-
"
|
15
|
+
"non répertorié dans l'annuaire Domino",
|
16
|
+
'no se encuentra en el Directorio de Domino',
|
17
17
|
'Domino ディレクトリには見つかりません',
|
18
18
|
],
|
19
19
|
'filtered' => ['Cannot route mail to user'],
|
@@ -25,7 +25,7 @@ module Sisimai::Lhost
|
|
25
25
|
# @param [String] mbody Message body of a bounce email
|
26
26
|
# @return [Hash] Bounce data list and message/rfc822 part
|
27
27
|
# @return [Nil] it failed to parse or the arguments are missing
|
28
|
-
def
|
28
|
+
def inquire(mhead, mbody)
|
29
29
|
return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:', 'DELIVERY_FAILURE:')
|
30
30
|
|
31
31
|
require 'sisimai/rfc1894'
|
@@ -33,16 +33,16 @@ module Sisimai::Lhost
|
|
33
33
|
permessage = {} # (Hash) Store values of each Per-Message field
|
34
34
|
|
35
35
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
36
|
-
|
37
|
-
bodyslices =
|
36
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
37
|
+
bodyslices = emailparts[0].split("\n")
|
38
38
|
readcursor = 0 # (Integer) Points the current cursor position
|
39
39
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
40
40
|
subjecttxt = '' # (String) The value of Subject:
|
41
41
|
v = nil
|
42
42
|
|
43
43
|
while e = bodyslices.shift do
|
44
|
-
# Read error messages and delivery status lines from the head of the email
|
45
|
-
#
|
44
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
45
|
+
# line of the beginning of the original message.
|
46
46
|
next if e.empty?
|
47
47
|
|
48
48
|
if readcursor == 0
|
@@ -76,10 +76,10 @@ module Sisimai::Lhost
|
|
76
76
|
v['recipient'] ||= e
|
77
77
|
recipients += 1
|
78
78
|
|
79
|
-
elsif
|
79
|
+
elsif e.start_with?(' ') && e.include?('@') && e.index(' ', 3).nil?
|
80
80
|
# Continued from the line "was not delivered to:"
|
81
81
|
# kijitora@example.net
|
82
|
-
v['recipient'] = Sisimai::Address.s3s4(
|
82
|
+
v['recipient'] = Sisimai::Address.s3s4(e[2, e.size])
|
83
83
|
|
84
84
|
elsif e.start_with?('because:')
|
85
85
|
# because:
|
@@ -89,9 +89,9 @@ module Sisimai::Lhost
|
|
89
89
|
# Error message, continued from the line "because:"
|
90
90
|
v['diagnosis'] = e
|
91
91
|
|
92
|
-
elsif
|
92
|
+
elsif e.start_with?(' Subject: ')
|
93
93
|
# Subject: Nyaa
|
94
|
-
subjecttxt =
|
94
|
+
subjecttxt = e[11, e.size]
|
95
95
|
|
96
96
|
elsif f = Sisimai::RFC1894.match(e)
|
97
97
|
# There are some fields defined in RFC3464, try to match
|
@@ -107,9 +107,14 @@ module Sisimai::Lhost
|
|
107
107
|
next unless fieldtable[o[0]]
|
108
108
|
v[fieldtable[o[0]]] = o[2]
|
109
109
|
|
110
|
-
next unless f
|
110
|
+
next unless f
|
111
111
|
permessage[fieldtable[o[0]]] = o[2]
|
112
112
|
end
|
113
|
+
else
|
114
|
+
if v['diagnosis'] && e.start_with?("\s", "\t")
|
115
|
+
# The line is a continued line of "Diagnostic-Code:" field
|
116
|
+
v['diagnosis'] += e.sub(/\A[\s\t]+/, '')
|
117
|
+
end
|
113
118
|
end
|
114
119
|
end
|
115
120
|
end
|
@@ -130,11 +135,10 @@ module Sisimai::Lhost
|
|
130
135
|
end
|
131
136
|
end
|
132
137
|
|
133
|
-
# Set the value of subjecttxt as a Subject if there is no original
|
134
|
-
|
135
|
-
emailsteak[1] << ('Subject: ' << subjecttxt << "\n") unless emailsteak[1] =~ /^Subject: /
|
138
|
+
# Set the value of subjecttxt as a Subject if there is no original message in the bounce mail.
|
139
|
+
emailparts[1] << ('Subject: ' << subjecttxt << "\n") unless emailparts[1].include?("\nSubject:")
|
136
140
|
|
137
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
141
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
138
142
|
end
|
139
143
|
def description; return 'IBM Domino Server'; end
|
140
144
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::EinsUndEins parses a bounce email which created by
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::EinsUndEins parses a bounce email which created by 1&1. Methods in the module are
|
3
|
+
# called from only Sisimai::Message.
|
4
4
|
module EinsUndEins
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/EinsUndEins.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['--- The header of the original message is following. ---'].freeze
|
11
10
|
StartingOf = {
|
12
11
|
message: ['This message was created automatically by mail delivery software'],
|
13
12
|
error: ['For the following reason:'],
|
@@ -19,20 +18,20 @@ module Sisimai::Lhost
|
|
19
18
|
# @param [String] mbody Message body of a bounce email
|
20
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
21
20
|
# @return [Nil] it failed to parse or the arguments are missing
|
22
|
-
def
|
21
|
+
def inquire(mhead, mbody)
|
23
22
|
return nil unless mhead['from'].start_with?('"Mail Delivery System"')
|
24
23
|
return nil unless mhead['subject'] == 'Mail delivery failed: returning message to sender'
|
25
24
|
|
26
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
27
|
-
|
28
|
-
bodyslices =
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
29
28
|
readcursor = 0 # (Integer) Points the current cursor position
|
30
29
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
31
30
|
v = nil
|
32
31
|
|
33
32
|
while e = bodyslices.shift do
|
34
|
-
# Read error messages and delivery status lines from the head of the email
|
35
|
-
#
|
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.
|
36
35
|
|
37
36
|
if readcursor == 0
|
38
37
|
# Beginning of the bounce message or delivery status part
|
@@ -52,14 +51,15 @@ module Sisimai::Lhost
|
|
52
51
|
# http://postmaster.1and1.com/en/error-messages?ip=%1s
|
53
52
|
v = dscontents[-1]
|
54
53
|
|
55
|
-
if cv = e.match(/\A([^ ]+[@][^ ]+?)[:]?\z/)
|
56
|
-
# general@example.eu
|
54
|
+
if cv = e.match(/\A\s*([^ ]+[@][^ ]+?)[:]?\z/)
|
55
|
+
# general@example.eu OR
|
56
|
+
# the line begin with 4 space characters, end with ":" like " neko@example.eu:"
|
57
57
|
if v['recipient']
|
58
58
|
# There are multiple recipient addresses in the message body.
|
59
59
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
60
60
|
v = dscontents[-1]
|
61
61
|
end
|
62
|
-
v['recipient'] =
|
62
|
+
v['recipient'] = Sisimai::Address.s3s4(e)
|
63
63
|
recipients += 1
|
64
64
|
|
65
65
|
elsif e.start_with?(StartingOf[:error][0])
|
@@ -80,21 +80,26 @@ module Sisimai::Lhost
|
|
80
80
|
end
|
81
81
|
return nil unless recipients > 0
|
82
82
|
|
83
|
+
require 'sisimai/smtp/command'
|
83
84
|
dscontents.each do |e|
|
84
85
|
e['diagnosis'] ||= ''
|
85
86
|
e['diagnosis'] = e['alterrors'] if e['diagnosis'].empty?
|
87
|
+
e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
|
86
88
|
|
87
|
-
if
|
89
|
+
if Sisimai::String.aligned(e['diagnosis'], ['host: ', ' reason:'])
|
88
90
|
# SMTP error from remote server for TEXT command,
|
89
91
|
# host: smtp-in.orange.fr (193.252.22.65)
|
90
92
|
# reason: 550 5.2.0 Mail rejete. Mail rejected. ofr_506 [506]
|
91
|
-
e['
|
92
|
-
|
93
|
-
|
93
|
+
p1 = e['diagnosis'].index('host: ')
|
94
|
+
p2 = e['diagnosis'].index(' reason:')
|
95
|
+
|
96
|
+
e['rhost'] = Sisimai::String.sweep(e['diagnosis'][p1 + 6, p2 - p1 - 6])
|
97
|
+
e['command'] = 'DATA' if e['diagnosis'].include?('for TEXT command')
|
98
|
+
e['spec'] = 'SMTP' if e['diagnosis'].include?('SMTP error')
|
94
99
|
e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
|
95
100
|
else
|
96
101
|
# For the following reason:
|
97
|
-
e['diagnosis']
|
102
|
+
e['diagnosis'][0, StartingOf[:error][0].size] = ''
|
98
103
|
end
|
99
104
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
100
105
|
|
@@ -106,7 +111,7 @@ module Sisimai::Lhost
|
|
106
111
|
end
|
107
112
|
end
|
108
113
|
|
109
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
114
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
110
115
|
end
|
111
116
|
def description; return '1&1: https://www.1und1.de'; end
|
112
117
|
end
|