sisimai 4.25.16-java → 5.0.2-java
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 +5 -5
- data/.github/workflows/rake-test.yml +55 -0
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +451 -393
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +323 -149
- data/README.md +319 -149
- 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 +506 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -42
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -19
- data/lib/sisimai/lhost/aol.rb +12 -15
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -22
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -20
- 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 +179 -174
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -34
- 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 +11 -11
- data/lib/sisimai/lhost/gsuite.rb +21 -28
- 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 +37 -40
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -21
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +16 -17
- data/lib/sisimai/lhost/mxlogic.rb +24 -33
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +64 -28
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -16
- data/lib/sisimai/lhost/postfix.rb +179 -130
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -21
- data/lib/sisimai/lhost/sendgrid.rb +34 -34
- data/lib/sisimai/lhost/sendmail.rb +65 -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 -21
- 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 +444 -326
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +65 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +96 -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 +7 -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 +11 -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 +34 -36
- data/lib/sisimai/reason/spamdetected.rb +115 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +12 -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 +177 -146
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/google.rb +530 -0
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +51 -42
- data/lib/sisimai/rhost/nttdocomo.rb +12 -12
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +507 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +46 -31
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/lhost-sendmail-60.eml +85 -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 +48 -26
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- data/lib/sisimai/rhost/googleapps.rb +0 -261
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
data/lib/sisimai/lhost/kddi.rb
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::KDDI parses a bounce email which created by au by KDDI.
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::KDDI parses a bounce email which created by au by KDDI. Methods in the module are
|
|
3
|
+
# called from only Sisimai::Message.
|
|
4
4
|
module KDDI
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/KDDI.pm
|
|
7
6
|
require 'sisimai/lhost'
|
|
8
7
|
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
10
|
-
|
|
11
|
-
MarkingsOf = {
|
|
12
|
-
message: %r/\AYour[ ]mail[ ](?:
|
|
13
|
-
sent[ ]on:?[ ][A-Z][a-z]{2}[,]
|
|
14
|
-
|attempted[ ]to[ ]be[ ]delivered[ ]on:?[ ][A-Z][a-z]{2}[,]
|
|
15
|
-
)
|
|
16
|
-
/x,
|
|
17
|
-
}.freeze
|
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
|
10
|
+
MarkingsOf = { message: ['Your mail sent on:', 'Your mail attempted to be delivered on:'] }.freeze
|
|
18
11
|
MessagesOf = {
|
|
19
12
|
'mailboxfull' => ['As their mailbox is full'],
|
|
20
13
|
'norelaying' => ['Due to the following SMTP relay error'],
|
|
@@ -26,35 +19,35 @@ module Sisimai::Lhost
|
|
|
26
19
|
# @param [String] mbody Message body of a bounce email
|
|
27
20
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
28
21
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
29
|
-
def
|
|
22
|
+
def inquire(mhead, mbody)
|
|
30
23
|
# :'message-id' => %r/[@].+[.]ezweb[.]ne[.]jp[>]\z/,
|
|
31
24
|
match = 0
|
|
32
|
-
match += 1 if mhead['from']
|
|
25
|
+
match += 1 if Sisimai::String.aligned(mhead['from'], ['no-reply@.', '.dion.ne.jp'])
|
|
33
26
|
match += 1 if mhead['reply-to'].to_s == 'no-reply@app.auone-net.jp'
|
|
34
27
|
match += 1 if mhead['received'].any? { |a| a.include?('ezweb.ne.jp (') }
|
|
35
28
|
match += 1 if mhead['received'].any? { |a| a.include?('.au.com (') }
|
|
36
29
|
return nil unless match > 0
|
|
37
30
|
|
|
38
31
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
39
|
-
|
|
40
|
-
bodyslices =
|
|
32
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
33
|
+
bodyslices = emailparts[0].split("\n")
|
|
41
34
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
42
35
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
43
36
|
v = nil
|
|
44
37
|
|
|
45
38
|
while e = bodyslices.shift do
|
|
46
|
-
# Read error messages and delivery status lines from the head of the email
|
|
47
|
-
#
|
|
39
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
|
40
|
+
# line of the beginning of the original message.
|
|
48
41
|
if readcursor == 0
|
|
49
42
|
# Beginning of the bounce message or delivery status part
|
|
50
|
-
readcursor |= Indicators[:deliverystatus] if
|
|
43
|
+
readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.start_with?(a) }
|
|
51
44
|
next
|
|
52
45
|
end
|
|
53
46
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
|
54
47
|
next if e.empty?
|
|
55
48
|
|
|
56
49
|
v = dscontents[-1]
|
|
57
|
-
if
|
|
50
|
+
if e.include?(' Could not be delivered to: <')
|
|
58
51
|
# Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
|
|
59
52
|
# Could not be delivered to: <******@**.***.**>
|
|
60
53
|
# As their mailbox is full.
|
|
@@ -63,24 +56,26 @@ module Sisimai::Lhost
|
|
|
63
56
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
64
57
|
v = dscontents[-1]
|
|
65
58
|
end
|
|
66
|
-
r = Sisimai::Address.s3s4(
|
|
67
|
-
next unless Sisimai::
|
|
59
|
+
r = Sisimai::Address.s3s4(e[e.index('<') + 1, e.size])
|
|
60
|
+
next unless Sisimai::Address.is_emailaddress(r)
|
|
68
61
|
v['recipient'] = r
|
|
69
62
|
recipients += 1
|
|
70
63
|
|
|
71
|
-
elsif
|
|
64
|
+
elsif e.include?('Your mail sent on: ')
|
|
72
65
|
# Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
|
|
73
|
-
v['date'] =
|
|
66
|
+
v['date'] = e[19, e.size]
|
|
74
67
|
else
|
|
75
68
|
# As their mailbox is full.
|
|
76
69
|
v['diagnosis'] ||= ''
|
|
77
|
-
v['diagnosis'] << e + ' ' if e.start_with?(' '
|
|
70
|
+
v['diagnosis'] << e + ' ' if e.start_with?(' ')
|
|
78
71
|
end
|
|
79
72
|
end
|
|
80
73
|
return nil unless recipients > 0
|
|
81
74
|
|
|
75
|
+
require 'sisimai/smtp/command'
|
|
82
76
|
dscontents.each do |e|
|
|
83
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
77
|
+
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
|
78
|
+
e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
|
|
84
79
|
|
|
85
80
|
if mhead['x-spasign'].to_s == 'NG'
|
|
86
81
|
# Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by KDDI)
|
|
@@ -88,8 +83,7 @@ module Sisimai::Lhost
|
|
|
88
83
|
e['reason'] = 'filtered'
|
|
89
84
|
else
|
|
90
85
|
if e['command'] == 'RCPT'
|
|
91
|
-
# set "userunknown" when the remote server rejected after RCPT
|
|
92
|
-
# command.
|
|
86
|
+
# set "userunknown" when the remote server rejected after RCPT command.
|
|
93
87
|
e['reason'] = 'userunknown'
|
|
94
88
|
else
|
|
95
89
|
# SMTP command is not RCPT
|
|
@@ -104,7 +98,7 @@ module Sisimai::Lhost
|
|
|
104
98
|
|
|
105
99
|
end
|
|
106
100
|
|
|
107
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
101
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
108
102
|
end
|
|
109
103
|
def description; return 'au by KDDI: https://www.au.kddi.com'; end
|
|
110
104
|
end
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::MailFoundry parses a bounce email which created by
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::MailFoundry parses a bounce email which created by MailFoundry. Methods in the
|
|
3
|
+
# module are called from only Sisimai::Message.
|
|
4
4
|
module MailFoundry
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MailFoundry.pm
|
|
7
6
|
require 'sisimai/lhost'
|
|
8
7
|
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
10
|
-
|
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
|
11
10
|
StartingOf = {
|
|
12
11
|
message: ['Unable to deliver message to:'],
|
|
13
12
|
error: ['Delivery failed for the following reason:'],
|
|
@@ -18,20 +17,20 @@ module Sisimai::Lhost
|
|
|
18
17
|
# @param [String] mbody Message body of a bounce email
|
|
19
18
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
20
19
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
21
|
-
def
|
|
20
|
+
def inquire(mhead, mbody)
|
|
22
21
|
return nil unless mhead['subject'] == 'Message delivery has failed'
|
|
23
22
|
return nil unless mhead['received'].any? { |a| a.include?('(MAILFOUNDRY) id ') }
|
|
24
23
|
|
|
25
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
26
|
-
|
|
27
|
-
bodyslices =
|
|
25
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
26
|
+
bodyslices = emailparts[0].split("\n")
|
|
28
27
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
29
28
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
30
29
|
v = nil
|
|
31
30
|
|
|
32
31
|
while e = bodyslices.shift do
|
|
33
|
-
# Read error messages and delivery status lines from the head of the email
|
|
34
|
-
#
|
|
32
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
|
33
|
+
# line of the beginning of the original message.
|
|
35
34
|
if readcursor == 0
|
|
36
35
|
# Beginning of the bounce message or delivery status part
|
|
37
36
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
|
@@ -46,14 +45,14 @@ module Sisimai::Lhost
|
|
|
46
45
|
# This has been a permanent failure. No further delivery attempts will be made.
|
|
47
46
|
v = dscontents[-1]
|
|
48
47
|
|
|
49
|
-
if
|
|
48
|
+
if e.start_with?('Unable to deliver message to: <') && e.index('@') > 1
|
|
50
49
|
# Unable to deliver message to: <kijitora@example.org>
|
|
51
50
|
if v['recipient']
|
|
52
51
|
# There are multiple recipient addresses in the message body.
|
|
53
52
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
54
53
|
v = dscontents[-1]
|
|
55
54
|
end
|
|
56
|
-
v['recipient'] =
|
|
55
|
+
v['recipient'] = e[e.index('<'), e.size]
|
|
57
56
|
recipients += 1
|
|
58
57
|
else
|
|
59
58
|
# Error message
|
|
@@ -74,7 +73,7 @@ module Sisimai::Lhost
|
|
|
74
73
|
return nil unless recipients > 0
|
|
75
74
|
|
|
76
75
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
|
77
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
76
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
78
77
|
end
|
|
79
78
|
def description; return 'MailFoundry'; end
|
|
80
79
|
end
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::MailMarshalSMTP parses a bounce email which created
|
|
3
|
-
#
|
|
4
|
-
# the module are called from only Sisimai::Message.
|
|
2
|
+
# Sisimai::Lhost::MailMarshalSMTP parses a bounce email which created by Trustwave Secure Email
|
|
3
|
+
# Gateway: formerly MailMarshal SMTP. Methods in the module are called from only Sisimai::Message.
|
|
5
4
|
module MailMarshalSMTP
|
|
6
5
|
class << self
|
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MailMarshalSMTP.pm
|
|
8
6
|
require 'sisimai/lhost'
|
|
9
7
|
|
|
10
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
11
|
-
|
|
9
|
+
Boundaries = ['+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++']
|
|
12
10
|
StartingOf = {
|
|
13
11
|
message: ['Your message:'],
|
|
14
12
|
error: ['Could not be delivered because of'],
|
|
@@ -20,26 +18,19 @@ module Sisimai::Lhost
|
|
|
20
18
|
# @param [String] mbody Message body of a bounce email
|
|
21
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
22
20
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
23
|
-
def
|
|
21
|
+
def inquire(mhead, mbody)
|
|
24
22
|
return nil unless mhead['subject'].start_with?('Undeliverable Mail: "')
|
|
25
23
|
|
|
26
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
27
|
-
|
|
28
|
-
bodyslices =
|
|
25
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
26
|
+
bodyslices = emailparts[0].split("\n")
|
|
29
27
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
30
28
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
31
29
|
endoferror = false # (Boolean) Flag for the end of error message
|
|
32
30
|
regularexp = nil
|
|
31
|
+
q = Sisimai::RFC2045.boundary(mhead['content-type'], 1); Boundaries << q if q
|
|
33
32
|
v = nil
|
|
34
33
|
|
|
35
|
-
boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
|
|
36
|
-
regularexp = if boundary00.size > 0
|
|
37
|
-
# Convert to regular expression
|
|
38
|
-
Regexp.new('\A' << Regexp.escape(boundary00) << '\z')
|
|
39
|
-
else
|
|
40
|
-
regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
|
|
41
|
-
end
|
|
42
|
-
|
|
43
34
|
while e = bodyslices.shift do
|
|
44
35
|
# Read error messages and delivery status lines from the head of the email
|
|
45
36
|
# to the previous line of the beginning of the original message.
|
|
@@ -61,7 +52,7 @@ module Sisimai::Lhost
|
|
|
61
52
|
# dummyuser@blabla.xxxxxxxxxxxx.com
|
|
62
53
|
v = dscontents[-1]
|
|
63
54
|
|
|
64
|
-
if
|
|
55
|
+
if e.start_with?(' ') && e.index('@') > 1
|
|
65
56
|
# The following recipients were affected:
|
|
66
57
|
# dummyuser@blabla.xxxxxxxxxxxx.com
|
|
67
58
|
if v['recipient']
|
|
@@ -69,7 +60,7 @@ module Sisimai::Lhost
|
|
|
69
60
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
70
61
|
v = dscontents[-1]
|
|
71
62
|
end
|
|
72
|
-
v['recipient'] =
|
|
63
|
+
v['recipient'] = e[4, e.size]
|
|
73
64
|
recipients += 1
|
|
74
65
|
else
|
|
75
66
|
# Get error message lines
|
|
@@ -93,24 +84,29 @@ module Sisimai::Lhost
|
|
|
93
84
|
# Reporting-MTA: <relay.xxxxxxxxxxxx.com>
|
|
94
85
|
# MessageName: <B549996730000.000000000001.0003.mml>
|
|
95
86
|
# Last-Attempt-Date: <16:21:07 seg, 22 Dezembro 2014>
|
|
96
|
-
|
|
87
|
+
p1 = e.index('<')
|
|
88
|
+
p2 = e.index('>')
|
|
89
|
+
if e.start_with?('Original Sender: ')
|
|
97
90
|
# Original Sender: <originalsender@example.com>
|
|
98
|
-
# Use this line instead of "From" header of the original
|
|
99
|
-
|
|
100
|
-
emailsteak[1] << ('From: ' << cv[1] << "\n")
|
|
91
|
+
# Use this line instead of "From" header of the original message.
|
|
92
|
+
emailparts[1] << ('From: ' << e[p1 + 1, p2 - p1 - 1] << "\n")
|
|
101
93
|
|
|
102
|
-
elsif
|
|
94
|
+
elsif e.start_with?('Sender-MTA: ')
|
|
103
95
|
# Sender-MTA: <10.11.12.13>
|
|
104
|
-
v['lhost'] =
|
|
96
|
+
v['lhost'] = e[p1 + 1, p2 - p1 - 1]
|
|
105
97
|
|
|
106
|
-
elsif
|
|
98
|
+
elsif e.start_with?('Reporting-MTA: ')
|
|
107
99
|
# Reporting-MTA: <relay.xxxxxxxxxxxx.com>
|
|
108
|
-
v['rhost'] =
|
|
100
|
+
v['rhost'] = e[p1 + 1, p2 - p1 - 1]
|
|
109
101
|
|
|
110
|
-
elsif
|
|
102
|
+
elsif e.include?(' From:') || e.include?(' Subject:')
|
|
111
103
|
# From: originalsender@example.com
|
|
112
104
|
# Subject: ...
|
|
113
|
-
|
|
105
|
+
p1 = e.index(' From:') || e.index(' Subject:')
|
|
106
|
+
p2 = e.index(':')
|
|
107
|
+
cf = e[p1 + 1, p2 - p1 - 1]
|
|
108
|
+
cv = Sisimai::String.sweep(e[p2 + 1, e.size])
|
|
109
|
+
emailparts[1] << sprintf("%s: %s\n", cf, cv)
|
|
114
110
|
end
|
|
115
111
|
end
|
|
116
112
|
end
|
|
@@ -118,7 +114,7 @@ module Sisimai::Lhost
|
|
|
118
114
|
return nil unless recipients > 0
|
|
119
115
|
|
|
120
116
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
|
121
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
117
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
122
118
|
end
|
|
123
119
|
def description; return 'Trustwave Secure Email Gateway'; end
|
|
124
120
|
end
|
data/lib/sisimai/lhost/mailru.rb
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::MailRu parses a bounce email which created by @mail.ru.
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::MailRu parses a bounce email which created by @mail.ru. Methods in the module are
|
|
3
|
+
# called from only Sisimai::Message.
|
|
4
4
|
module MailRu
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/MailRu.pm
|
|
7
6
|
# Based on Sisimai::Lhost::Exim
|
|
8
7
|
require 'sisimai/lhost'
|
|
9
8
|
|
|
10
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
11
|
-
|
|
10
|
+
Boundaries = ['------ This is a copy of the message, including all the headers. ------'].freeze
|
|
12
11
|
StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
|
|
13
12
|
ReCommands = [
|
|
14
13
|
%r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
|
|
@@ -50,30 +49,31 @@ module Sisimai::Lhost
|
|
|
50
49
|
# @param [String] mbody Message body of a bounce email
|
|
51
50
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
52
51
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
53
|
-
def
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
def inquire(mhead, mbody)
|
|
53
|
+
mfrom = mhead['from'].downcase
|
|
54
|
+
msgid = mhead['message-id'] ? mhead['message-id'].downcase : ''
|
|
55
|
+
match = 0
|
|
56
|
+
match += 1 if mfrom.include?('mailer-daemon@') && mfrom.include?('mail.ru')
|
|
57
|
+
match += 1 if msgid.end_with?('.mail.ru>', 'smailru.net>')
|
|
58
|
+
match += 1 if [
|
|
59
|
+
'Delivery Status Notification',
|
|
60
|
+
'Mail delivery failed',
|
|
61
|
+
'Mail failure',
|
|
62
|
+
'Message frozen',
|
|
63
|
+
'Warning: message ',
|
|
64
|
+
'error(s) in forwarding or filtering'].any? { |a| mhead['subject'].include?(a) }
|
|
65
|
+
return nil unless match > 2
|
|
65
66
|
|
|
66
67
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
67
|
-
|
|
68
|
-
bodyslices =
|
|
68
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
69
|
+
bodyslices = emailparts[0].split("\n")
|
|
69
70
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
70
71
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
71
|
-
localhost0 = '' # (String) Local MTA
|
|
72
72
|
v = nil
|
|
73
73
|
|
|
74
74
|
while e = bodyslices.shift do
|
|
75
|
-
# Read error messages and delivery status lines from the head of the email
|
|
76
|
-
#
|
|
75
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
|
76
|
+
# line of the beginning of the original message.
|
|
77
77
|
if readcursor == 0
|
|
78
78
|
# Beginning of the bounce message or delivery status part
|
|
79
79
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
|
@@ -102,14 +102,14 @@ module Sisimai::Lhost
|
|
|
102
102
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
|
103
103
|
v = dscontents[-1]
|
|
104
104
|
|
|
105
|
-
if
|
|
105
|
+
if e.start_with?(' ') && e.include?(' ') == false && e.index('@') > 1
|
|
106
106
|
# kijitora@example.jp
|
|
107
107
|
if v['recipient']
|
|
108
108
|
# There are multiple recipient addresses in the message body.
|
|
109
109
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
110
110
|
v = dscontents[-1]
|
|
111
111
|
end
|
|
112
|
-
v['recipient'] =
|
|
112
|
+
v['recipient'] = e[2, e.size]
|
|
113
113
|
recipients += 1
|
|
114
114
|
|
|
115
115
|
elsif dscontents.size == recipients
|
|
@@ -120,7 +120,7 @@ module Sisimai::Lhost
|
|
|
120
120
|
else
|
|
121
121
|
# Error message when email address above does not include '@'
|
|
122
122
|
# and domain part.
|
|
123
|
-
next unless e.start_with?(' '
|
|
123
|
+
next unless e.start_with?(' ')
|
|
124
124
|
v['alterrors'] ||= ''
|
|
125
125
|
v['alterrors'] << e + ' '
|
|
126
126
|
end
|
|
@@ -144,16 +144,13 @@ module Sisimai::Lhost
|
|
|
144
144
|
end
|
|
145
145
|
return nil unless recipients > 0
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
end
|
|
147
|
+
# Get the name of the local MTA
|
|
148
|
+
# Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
|
|
149
|
+
receivedby = mhead['received'] || []
|
|
150
|
+
recvdtoken = Sisimai::RFC5322.received(receivedby[-1])
|
|
152
151
|
|
|
153
152
|
dscontents.each do |e|
|
|
154
|
-
#
|
|
155
|
-
e['lhost'] ||= localhost0
|
|
156
|
-
|
|
153
|
+
# Check the error message, the rhost, the lhost, and the smtp command.
|
|
157
154
|
unless e['alterrors'].to_s.empty?
|
|
158
155
|
# Copy alternative error message
|
|
159
156
|
e['diagnosis'] ||= e['alterrors']
|
|
@@ -164,18 +161,18 @@ module Sisimai::Lhost
|
|
|
164
161
|
e.delete('alterrors')
|
|
165
162
|
end
|
|
166
163
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
|
167
|
-
e['diagnosis'].
|
|
164
|
+
p1 = e['diagnosis'].rindex('__') || -1
|
|
165
|
+
e['diagnosis'] = e['diagnosis'][0, p1 - 1] if p1 > 2
|
|
168
166
|
|
|
169
167
|
unless e['rhost']
|
|
170
168
|
# Get the remote host name
|
|
171
169
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop unless mhead['received'].empty?
|
|
177
|
-
end
|
|
170
|
+
p1 = e['diagnosis'].index('host ') || -1
|
|
171
|
+
p2 = e['diagnosis'].index(' ', p1 + 5) || -1
|
|
172
|
+
e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
|
|
173
|
+
e['rhost'] ||= recvdtoken[1]
|
|
178
174
|
end
|
|
175
|
+
e['lhost'] ||= recvdtoken[0]
|
|
179
176
|
|
|
180
177
|
unless e['command']
|
|
181
178
|
# Get the SMTP command name for the session
|
|
@@ -208,7 +205,7 @@ module Sisimai::Lhost
|
|
|
208
205
|
e['command'] ||= ''
|
|
209
206
|
end
|
|
210
207
|
|
|
211
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
208
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
212
209
|
end
|
|
213
210
|
def description; return '@mail.ru: https://mail.ru'; end
|
|
214
211
|
end
|
data/lib/sisimai/lhost/mcafee.rb
CHANGED
|
@@ -1,49 +1,39 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::McAfee parses a bounce email which created by McAfee
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::McAfee parses a bounce email which created by McAfee Email Appliance. Methods in
|
|
3
|
+
# the module are called from only Sisimai::Message.
|
|
4
4
|
module McAfee
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/McAfee.pm
|
|
7
6
|
require 'sisimai/lhost'
|
|
8
7
|
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
10
|
-
|
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
|
11
10
|
StartingOf = { message: ['--- The following addresses had delivery problems ---'] }.freeze
|
|
12
|
-
|
|
13
|
-
'userunknown' => %r{(?:
|
|
14
|
-
[ ]User[ ][(].+[@].+[)][ ]unknown[.][ ]
|
|
15
|
-
|550[ ]Unknown[ ]user[ ][^ ]+[@][^ ]+
|
|
16
|
-
|550[ ][<].+?[@].+?[>][.]+[ ]User[ ]not[ ]exist
|
|
17
|
-
|No[ ]such[ ]user
|
|
18
|
-
)
|
|
19
|
-
}x,
|
|
20
|
-
}.freeze
|
|
11
|
+
MessagesOf = { 'userunknown' => [' User not exist', ' unknown.', '550 Unknown user ', 'No such user'] }.freeze
|
|
21
12
|
|
|
22
13
|
# Parse bounce messages from McAfee Email Appliance
|
|
23
14
|
# @param [Hash] mhead Message headers of a bounce email
|
|
24
15
|
# @param [String] mbody Message body of a bounce email
|
|
25
16
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
26
17
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
27
|
-
def
|
|
18
|
+
def inquire(mhead, mbody)
|
|
28
19
|
# X-NAI-Header: Modified by McAfee Email and Web Security Virtual Appliance
|
|
29
20
|
return nil unless mhead['x-nai-header']
|
|
30
21
|
return nil unless mhead['x-nai-header'].start_with?('Modified by McAfee ')
|
|
31
22
|
return nil unless mhead['subject'] == 'Delivery Status'
|
|
32
23
|
|
|
33
|
-
require 'sisimai/rfc1894'
|
|
34
24
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
|
35
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
36
|
-
|
|
37
|
-
bodyslices =
|
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
|
38
28
|
readslices = ['']
|
|
39
29
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
40
30
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
41
|
-
|
|
31
|
+
issuedcode = '' # (String) Alternative diagnostic message
|
|
42
32
|
v = nil
|
|
43
33
|
|
|
44
34
|
while e = bodyslices.shift do
|
|
45
|
-
# Read error messages and delivery status lines from the head of the email
|
|
46
|
-
#
|
|
35
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
|
36
|
+
# line of the beginning of the original message.
|
|
47
37
|
readslices << e # Save the current line for the next loop
|
|
48
38
|
|
|
49
39
|
if readcursor == 0
|
|
@@ -65,15 +55,15 @@ module Sisimai::Lhost
|
|
|
65
55
|
#
|
|
66
56
|
v = dscontents[-1]
|
|
67
57
|
|
|
68
|
-
if
|
|
58
|
+
if Sisimai::String.aligned(e, ['<', '@', '>', '(', ')'])
|
|
69
59
|
# <kijitora@example.co.jp> (Unknown user kijitora@example.co.jp)
|
|
70
60
|
if v['recipient']
|
|
71
61
|
# There are multiple recipient addresses in the message body.
|
|
72
62
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
73
63
|
v = dscontents[-1]
|
|
74
64
|
end
|
|
75
|
-
v['recipient'] =
|
|
76
|
-
|
|
65
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.index('>')])
|
|
66
|
+
issuedcode = e[e.index('(') + 1, e.size]
|
|
77
67
|
recipients += 1
|
|
78
68
|
|
|
79
69
|
elsif f = Sisimai::RFC1894.match(e)
|
|
@@ -82,8 +72,8 @@ module Sisimai::Lhost
|
|
|
82
72
|
unless o
|
|
83
73
|
# Fallback code for empty value or invalid formatted value
|
|
84
74
|
# - Original-Recipient: <kijitora@example.co.jp>
|
|
85
|
-
if
|
|
86
|
-
v['alias'] = Sisimai::Address.s3s4(
|
|
75
|
+
if e.start_with?('Original-Recipient: ')
|
|
76
|
+
v['alias'] = Sisimai::Address.s3s4(e[e.index(':') + 1, e.size])
|
|
87
77
|
end
|
|
88
78
|
next
|
|
89
79
|
end
|
|
@@ -93,24 +83,24 @@ module Sisimai::Lhost
|
|
|
93
83
|
else
|
|
94
84
|
# Continued line of the value of Diagnostic-Code field
|
|
95
85
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
|
96
|
-
next unless
|
|
97
|
-
v['diagnosis'] << ' ' <<
|
|
86
|
+
next unless e.start_with?(' ')
|
|
87
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
|
98
88
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
|
99
89
|
end
|
|
100
90
|
end
|
|
101
91
|
return nil unless recipients > 0
|
|
102
92
|
|
|
103
93
|
dscontents.each do |e|
|
|
104
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] ||
|
|
105
|
-
|
|
94
|
+
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode)
|
|
95
|
+
MessagesOf.each_key do |r|
|
|
106
96
|
# Verify each regular expression of session errors
|
|
107
|
-
next unless e['diagnosis']
|
|
97
|
+
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
|
108
98
|
e['reason'] = r
|
|
109
99
|
break
|
|
110
100
|
end
|
|
111
101
|
end
|
|
112
102
|
|
|
113
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
103
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
114
104
|
end
|
|
115
105
|
def description; return 'McAfee Email Appliance'; end
|
|
116
106
|
end
|