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/gmx.rb
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::GMX parses a bounce email which created by GMX.
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::GMX parses a bounce email which created by GMX. Methods in the module are called
|
|
3
|
+
# from only Sisimai::Message.
|
|
4
4
|
module GMX
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/GMX.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 = { message: ['This message was created automatically by mail delivery software'] }.freeze
|
|
12
11
|
MessagesOf = { 'expired' => ['delivery retry timeout exceeded'] }.freeze
|
|
13
12
|
|
|
@@ -16,23 +15,24 @@ module Sisimai::Lhost
|
|
|
16
15
|
# @param [String] mbody Message body of a bounce email
|
|
17
16
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
18
17
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
19
|
-
def
|
|
18
|
+
def inquire(mhead, mbody)
|
|
20
19
|
# Envelope-To: <kijitora@mail.example.com>
|
|
21
20
|
# X-GMX-Antispam: 0 (Mail was not recognized as spam); Detail=V3;
|
|
22
21
|
# X-GMX-Antivirus: 0 (no virus found)
|
|
23
22
|
# X-UI-Out-Filterresults: unknown:0;
|
|
24
23
|
return nil unless mhead['x-gmx-antispam']
|
|
25
24
|
|
|
25
|
+
require 'sisimai/smtp/command'
|
|
26
26
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
27
|
-
|
|
28
|
-
bodyslices =
|
|
27
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
28
|
+
bodyslices = emailparts[0].split("\n")
|
|
29
29
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
30
30
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
31
31
|
v = nil
|
|
32
32
|
|
|
33
33
|
while e = bodyslices.shift do
|
|
34
|
-
# Read error messages and delivery status lines from the head of the email
|
|
35
|
-
#
|
|
34
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
|
35
|
+
# line of the beginning of the original message.
|
|
36
36
|
if readcursor == 0
|
|
37
37
|
# Beginning of the bounce message or delivery status part
|
|
38
38
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
|
@@ -53,7 +53,7 @@ module Sisimai::Lhost
|
|
|
53
53
|
# 5.1.1 <shironeko@example.jp>... User Unknown
|
|
54
54
|
v = dscontents[-1]
|
|
55
55
|
|
|
56
|
-
if
|
|
56
|
+
if e.include?('@') && ( e.start_with?('"') || e.start_with?('<') )
|
|
57
57
|
# "shironeko@example.jp":
|
|
58
58
|
# ---- OR ----
|
|
59
59
|
# <kijitora@6jo.example.co.jp>
|
|
@@ -65,19 +65,20 @@ module Sisimai::Lhost
|
|
|
65
65
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
66
66
|
v = dscontents[-1]
|
|
67
67
|
end
|
|
68
|
-
v['recipient'] =
|
|
68
|
+
v['recipient'] = Sisimai::Address.s3s4(e)
|
|
69
69
|
recipients += 1
|
|
70
70
|
|
|
71
|
-
elsif
|
|
71
|
+
elsif e.start_with?('SMTP error ')
|
|
72
72
|
# SMTP error from remote server after RCPT command:
|
|
73
|
-
v['command'] =
|
|
73
|
+
v['command'] = Sisimai::SMTP::Command.find(e)
|
|
74
74
|
|
|
75
|
-
elsif
|
|
75
|
+
elsif e.start_with?('host:')
|
|
76
76
|
# host: mx.example.jp
|
|
77
|
-
v['rhost'] =
|
|
77
|
+
v['rhost'] = e[6, e.size]
|
|
78
78
|
else
|
|
79
79
|
# Get error message
|
|
80
|
-
if e
|
|
80
|
+
if Sisimai::SMTP::Status.find(e) || Sisimai::String.aligned(e, ['<', '@', '>'])
|
|
81
|
+
# 5.1.1 <shironeko@example.jp>... User Unknown
|
|
81
82
|
v['diagnosis'] ||= e
|
|
82
83
|
else
|
|
83
84
|
next if e.empty?
|
|
@@ -105,7 +106,7 @@ module Sisimai::Lhost
|
|
|
105
106
|
end
|
|
106
107
|
end
|
|
107
108
|
|
|
108
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
109
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
109
110
|
end
|
|
110
111
|
def description; return 'GMX: https://www.gmx.net'; end
|
|
111
112
|
end
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::GoogleGroups parses a bounce email which created by Google
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::GoogleGroups parses a bounce email which created by Google Groups. Methods in the
|
|
3
|
+
# module are called from only Sisimai::Message.
|
|
4
4
|
module GoogleGroups
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/GoogleGroups.pm
|
|
7
6
|
require 'sisimai/lhost'
|
|
8
7
|
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
10
|
-
|
|
9
|
+
Boundaries = ['----- Original message -----'].freeze
|
|
11
10
|
|
|
12
11
|
# Parse bounce messages from Google Groups
|
|
13
12
|
# @param [Hash] mhead Message headers of a bounce email
|
|
@@ -15,7 +14,7 @@ module Sisimai::Lhost
|
|
|
15
14
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
16
15
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
17
16
|
# @since v4.25.6
|
|
18
|
-
def
|
|
17
|
+
def inquire(mhead, mbody)
|
|
19
18
|
return nil unless mhead['from'].end_with?('<mailer-daemon@googlemail.com>')
|
|
20
19
|
return nil unless mhead['subject'].start_with?('Delivery Status Notification')
|
|
21
20
|
return nil unless mhead['x-failed-recipients']
|
|
@@ -39,7 +38,7 @@ module Sisimai::Lhost
|
|
|
39
38
|
#
|
|
40
39
|
# Google Groups
|
|
41
40
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
42
|
-
|
|
41
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
43
42
|
recordwide = { 'rhost' => '', 'reason' => '', 'diagnosis' => '' }
|
|
44
43
|
recipients = 0
|
|
45
44
|
v = dscontents[-1]
|
|
@@ -48,14 +47,15 @@ module Sisimai::Lhost
|
|
|
48
47
|
# * The owner of the group may have removed this group.
|
|
49
48
|
# * You may need to join the group before receiving permission to post.
|
|
50
49
|
# * This group may not be open to posting.
|
|
51
|
-
entiremesg =
|
|
50
|
+
entiremesg = emailparts[0].split(/\n\n/, 5).slice(0, 4).join(' ').tr("\n", ' ');
|
|
51
|
+
receivedby = mhead['received'] || []
|
|
52
52
|
recordwide['diagnosis'] = Sisimai::String.sweep(entiremesg)
|
|
53
|
-
recordwide['reason'] =
|
|
54
|
-
recordwide['rhost'] = Sisimai::RFC5322.received(
|
|
53
|
+
recordwide['reason'] = emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4 ? 'rejected' : 'onhold'
|
|
54
|
+
recordwide['rhost'] = Sisimai::RFC5322.received(receivedby[0])[1]
|
|
55
55
|
|
|
56
56
|
mhead['x-failed-recipients'].split(',').each do |e|
|
|
57
57
|
# X-Failed-Recipients: neko@example.jp, nyaan@example.org, ...
|
|
58
|
-
next unless Sisimai::
|
|
58
|
+
next unless Sisimai::Address.is_emailaddress(e)
|
|
59
59
|
|
|
60
60
|
if v['recipient']
|
|
61
61
|
# There are multiple recipient addresses in the message body.
|
|
@@ -67,7 +67,7 @@ module Sisimai::Lhost
|
|
|
67
67
|
recordwide.each_key { |r| v[r] = recordwide[r] }
|
|
68
68
|
end
|
|
69
69
|
return nil unless recipients > 0
|
|
70
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
70
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
71
71
|
end
|
|
72
72
|
def description; return 'Google Groups: https://groups.google.com'; end
|
|
73
73
|
end
|
data/lib/sisimai/lhost/gsuite.rb
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::GSuite parses a bounce email which created by G Suite.
|
|
3
|
-
#
|
|
2
|
+
# Sisimai::Lhost::GSuite parses a bounce email which created by G Suite. Methods in the module are
|
|
3
|
+
# called from only Sisimai::Message.
|
|
4
4
|
module GSuite
|
|
5
5
|
class << self
|
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/GSuite.pm
|
|
7
6
|
require 'sisimai/lhost'
|
|
8
7
|
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
10
|
-
|
|
9
|
+
Boundaries = ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'].freeze
|
|
11
10
|
MarkingsOf = {
|
|
12
|
-
message:
|
|
13
|
-
error:
|
|
14
|
-
html: %r{\AContent-Type:[ ]*text/html;[ ]*charset=['"]?(?:UTF|utf)[-]8['"]?\z},
|
|
11
|
+
message: ['** '],
|
|
12
|
+
error: ['The response was:', 'The response from the remote server was:'],
|
|
15
13
|
}.freeze
|
|
16
14
|
MessagesOf = {
|
|
17
15
|
'userunknown' => ["because the address couldn't be found. Check for typos or unnecessary spaces and try again."],
|
|
@@ -24,18 +22,17 @@ module Sisimai::Lhost
|
|
|
24
22
|
# @param [String] mbody Message body of a bounce email
|
|
25
23
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
26
24
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
27
|
-
def
|
|
25
|
+
def inquire(mhead, mbody)
|
|
28
26
|
return nil unless mhead['from'].end_with?('<mailer-daemon@googlemail.com>')
|
|
29
27
|
return nil unless mhead['subject'].start_with?('Delivery Status Notification')
|
|
30
28
|
return nil unless mhead['x-gm-message-state']
|
|
31
29
|
|
|
32
|
-
require 'sisimai/rfc1894'
|
|
33
30
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
|
34
31
|
permessage = {} # (Hash) Store values of each Per-Message field
|
|
35
32
|
|
|
36
33
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
37
|
-
|
|
38
|
-
bodyslices =
|
|
34
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
35
|
+
bodyslices = emailparts[0].split("\n")
|
|
39
36
|
readcursor = 0 # (Integer) Points the current cursor position
|
|
40
37
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
41
38
|
endoferror = false # (Integer) Flag for a blank line after error messages
|
|
@@ -44,11 +41,11 @@ module Sisimai::Lhost
|
|
|
44
41
|
v = nil
|
|
45
42
|
|
|
46
43
|
while e = bodyslices.shift do
|
|
47
|
-
# Read error messages and delivery status lines from the head of the email
|
|
48
|
-
#
|
|
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.
|
|
49
46
|
if readcursor == 0
|
|
50
47
|
# Beginning of the bounce message or message/delivery-status part
|
|
51
|
-
readcursor |= Indicators[:deliverystatus] if
|
|
48
|
+
readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.start_with?(a) }
|
|
52
49
|
end
|
|
53
50
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
|
54
51
|
|
|
@@ -87,12 +84,12 @@ module Sisimai::Lhost
|
|
|
87
84
|
v['lhost'] = '' if v['lhost'].include?('@')
|
|
88
85
|
end
|
|
89
86
|
|
|
90
|
-
next unless f
|
|
87
|
+
next unless f
|
|
91
88
|
permessage[fieldtable[o[0]]] = o[2]
|
|
92
89
|
end
|
|
93
90
|
else
|
|
94
|
-
# The line does not begin with a DSN field defined in RFC3464
|
|
95
|
-
#
|
|
91
|
+
# The line does not begin with a DSN field defined in RFC3464 Append error messages continued
|
|
92
|
+
# from the previous line
|
|
96
93
|
if endoferror == false && v && ! v['diagnosis'].to_s.empty?
|
|
97
94
|
endoferror ||= true if e.empty?
|
|
98
95
|
|
|
@@ -100,10 +97,10 @@ module Sisimai::Lhost
|
|
|
100
97
|
next unless e.start_with?(' ')
|
|
101
98
|
v['diagnosis'] << e
|
|
102
99
|
|
|
103
|
-
elsif
|
|
100
|
+
elsif MarkingsOf[:error].any? { |a| e.start_with?(a) }
|
|
104
101
|
# Detect SMTP session error or connection error
|
|
105
102
|
# The response from the remote server was:
|
|
106
|
-
anotherset['diagnosis'] << e
|
|
103
|
+
anotherset['diagnosis'] << ' ' << e
|
|
107
104
|
else
|
|
108
105
|
# ** Address not found **
|
|
109
106
|
#
|
|
@@ -112,12 +109,9 @@ module Sisimai::Lhost
|
|
|
112
109
|
#
|
|
113
110
|
# The response from the remote server was:
|
|
114
111
|
# 550 #5.1.0 Address rejected.
|
|
115
|
-
next if e
|
|
116
|
-
|
|
112
|
+
next if e.start_with?('Content-Type:')
|
|
117
113
|
if anotherset['diagnosis']
|
|
118
|
-
# Continued error messages from the previous line like
|
|
119
|
-
# "550 #5.1.0 Address rejected."
|
|
120
|
-
next if e =~ /\AContent-Type:/
|
|
114
|
+
# Continued error messages from the previous line like "550 #5.1.0 Address rejected."
|
|
121
115
|
next if emptylines > 5
|
|
122
116
|
if e.empty?
|
|
123
117
|
# Count and next()
|
|
@@ -131,7 +125,7 @@ module Sisimai::Lhost
|
|
|
131
125
|
# Your message wasn't delivered to * because the address couldn't be found.
|
|
132
126
|
# Check for typos or unnecessary spaces and try again.
|
|
133
127
|
next if e.empty?
|
|
134
|
-
next unless
|
|
128
|
+
next unless MarkingsOf[:message].any? { |a| e.start_with?(a) }
|
|
135
129
|
anotherset['diagnosis'] = e
|
|
136
130
|
end
|
|
137
131
|
end
|
|
@@ -141,14 +135,13 @@ module Sisimai::Lhost
|
|
|
141
135
|
|
|
142
136
|
dscontents.each do |e|
|
|
143
137
|
# Set default values if each value is empty.
|
|
144
|
-
e['lhost'] ||= permessage['rhost']
|
|
145
138
|
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
|
146
139
|
|
|
147
140
|
if anotherset['diagnosis']
|
|
148
141
|
# Copy alternative error message
|
|
149
142
|
e['diagnosis'] = anotherset['diagnosis'] unless e['diagnosis']
|
|
150
143
|
|
|
151
|
-
if e['diagnosis']
|
|
144
|
+
if e['diagnosis'].include?(' ') == false && e['diagnosis'].to_i > 0
|
|
152
145
|
e['diagnosis'] = anotherset['diagnosis']
|
|
153
146
|
else
|
|
154
147
|
# More detailed error message is in "anotherset"
|
|
@@ -192,7 +185,7 @@ module Sisimai::Lhost
|
|
|
192
185
|
end
|
|
193
186
|
end
|
|
194
187
|
|
|
195
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
188
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
196
189
|
end
|
|
197
190
|
def description; return 'G Suite: https://gsuite.google.com'; end
|
|
198
191
|
end
|
|
@@ -1,29 +1,19 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::IMailServer parses a bounce email which created by
|
|
3
|
-
# Ipswitch IMail Server.
|
|
2
|
+
# Sisimai::Lhost::IMailServer parses a bounce email which created by Ipswitch IMail Server.
|
|
4
3
|
# Methods in the module are called from only Sisimai::Message.
|
|
5
4
|
module IMailServer
|
|
6
5
|
class << self
|
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/IMailServer.pm
|
|
8
6
|
require 'sisimai/lhost'
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
Boundaries = ['Original message follows.'].freeze
|
|
11
9
|
StartingOf = { error: ['Body of message generated response:'] }.freeze
|
|
12
|
-
|
|
13
|
-
ReSMTP = {
|
|
14
|
-
'conn' => %r/(?:SMTP connection failed,|Unexpected connection response from server:)/,
|
|
15
|
-
'ehlo' => %r|Unexpected response to EHLO/HELO:|,
|
|
16
|
-
'mail' => %r|Server response to MAIL FROM:|,
|
|
17
|
-
'rcpt' => %r|Additional RCPT TO generated following response:|,
|
|
18
|
-
'data' => %r|DATA command generated response:|,
|
|
19
|
-
}.freeze
|
|
20
10
|
ReFailures = {
|
|
21
|
-
'hostunknown' =>
|
|
22
|
-
'userunknown' =>
|
|
23
|
-
'mailboxfull' =>
|
|
24
|
-
'virusdetected' =>
|
|
25
|
-
'undefined' =>
|
|
26
|
-
'expired' =>
|
|
11
|
+
'hostunknown' => ['Unknown host'],
|
|
12
|
+
'userunknown' => ['Unknown user', 'Invalid final delivery userid'],
|
|
13
|
+
'mailboxfull' => ['User mailbox exceeds allowed size'],
|
|
14
|
+
'virusdetected' => ['Requested action not taken: virus detected'],
|
|
15
|
+
'undefined' => ['undeliverable to'],
|
|
16
|
+
'expired' => ['Delivery failed '],
|
|
27
17
|
}.freeze
|
|
28
18
|
|
|
29
19
|
# Parse bounce messages from IMailServer
|
|
@@ -31,47 +21,48 @@ module Sisimai::Lhost
|
|
|
31
21
|
# @param [String] mbody Message body of a bounce email
|
|
32
22
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
33
23
|
# @return [Nil] it failed to parse or the arguments are missing
|
|
34
|
-
def
|
|
24
|
+
def inquire(mhead, mbody)
|
|
35
25
|
# X-Mailer: <SMTP32 v8.22>
|
|
36
26
|
match = 0
|
|
37
|
-
match += 1 if mhead['subject']
|
|
27
|
+
match += 1 if mhead['subject'].start_with?('Undeliverable Mail ')
|
|
38
28
|
match += 1 if mhead['x-mailer'].to_s.start_with?('<SMTP32 v')
|
|
39
29
|
return nil unless match > 0
|
|
40
30
|
|
|
41
31
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
42
|
-
|
|
43
|
-
bodyslices =
|
|
32
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
33
|
+
bodyslices = emailparts[0].split("\n")
|
|
44
34
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
45
35
|
v = nil
|
|
46
36
|
|
|
47
37
|
while e = bodyslices.shift do
|
|
48
|
-
# Read error messages and delivery status lines from the head of the email
|
|
49
|
-
#
|
|
38
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
|
39
|
+
# line of the beginning of the original message.
|
|
50
40
|
|
|
51
41
|
# Unknown user: kijitora@example.com
|
|
52
42
|
#
|
|
53
43
|
# Original message follows.
|
|
54
44
|
v = dscontents[-1]
|
|
55
45
|
|
|
56
|
-
|
|
46
|
+
p0 = e.index(': ') || -1
|
|
47
|
+
if p0 > 8 && Sisimai::String.aligned(e, [': ', '@'])
|
|
57
48
|
# Unknown user: kijitora@example.com
|
|
58
49
|
if v['recipient']
|
|
59
50
|
# There are multiple recipient addresses in the message body.
|
|
60
51
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
61
52
|
v = dscontents[-1]
|
|
62
53
|
end
|
|
63
|
-
v['diagnosis'] =
|
|
64
|
-
v['recipient'] =
|
|
54
|
+
v['diagnosis'] = e
|
|
55
|
+
v['recipient'] = Sisimai::Address.s3s4(e[p0 + 2, e.size])
|
|
65
56
|
recipients += 1
|
|
66
57
|
|
|
67
|
-
elsif
|
|
58
|
+
elsif e.start_with?('undeliverable ')
|
|
68
59
|
# undeliverable to kijitora@example.com
|
|
69
60
|
if v['recipient']
|
|
70
61
|
# There are multiple recipient addresses in the message body.
|
|
71
62
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
72
63
|
v = dscontents[-1]
|
|
73
64
|
end
|
|
74
|
-
v['recipient'] = Sisimai::Address.s3s4(
|
|
65
|
+
v['recipient'] = Sisimai::Address.s3s4(e)
|
|
75
66
|
recipients += 1
|
|
76
67
|
else
|
|
77
68
|
# Other error message text
|
|
@@ -81,6 +72,7 @@ module Sisimai::Lhost
|
|
|
81
72
|
end
|
|
82
73
|
return nil unless recipients > 0
|
|
83
74
|
|
|
75
|
+
require 'sisimai/smtp/command'
|
|
84
76
|
dscontents.each do |e|
|
|
85
77
|
unless e['alterrors'].to_s.empty?
|
|
86
78
|
# Copy alternative error message
|
|
@@ -92,24 +84,18 @@ module Sisimai::Lhost
|
|
|
92
84
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
93
85
|
e.delete('alterrors')
|
|
94
86
|
end
|
|
95
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
96
|
-
|
|
97
|
-
ReSMTP.each_key do |r|
|
|
98
|
-
# Detect SMTP command from the message
|
|
99
|
-
next unless e['diagnosis'] =~ ReSMTP[r]
|
|
100
|
-
e['command'] = r.upcase
|
|
101
|
-
break
|
|
102
|
-
end
|
|
87
|
+
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
|
88
|
+
e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
|
|
103
89
|
|
|
104
90
|
ReFailures.each_key do |r|
|
|
105
91
|
# Verify each regular expression of session errors
|
|
106
|
-
next unless e['diagnosis']
|
|
92
|
+
next unless ReFailures[r].any? { |a| e['diagnosis'].include?(a) }
|
|
107
93
|
e['reason'] = r
|
|
108
94
|
break
|
|
109
95
|
end
|
|
110
96
|
end
|
|
111
97
|
|
|
112
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
98
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
113
99
|
end
|
|
114
100
|
def description; return 'IPSWITCH IMail Server'; end
|
|
115
101
|
end
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
module Sisimai::Lhost
|
|
2
|
-
# Sisimai::Lhost::InterScanMSS parses a bounce email which created by
|
|
3
|
-
#
|
|
4
|
-
# called from only Sisimai::Message.
|
|
2
|
+
# Sisimai::Lhost::InterScanMSS parses a bounce email which created by Trend Micro InterScan Messaging
|
|
3
|
+
# Security Suite. Methods in the module are called from only Sisimai::Message.
|
|
5
4
|
module InterScanMSS
|
|
6
5
|
class << self
|
|
7
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/InterScanMSS.pm
|
|
8
6
|
require 'sisimai/lhost'
|
|
9
|
-
|
|
7
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
|
10
8
|
|
|
11
9
|
# Parse bounce messages from InterScanMSS
|
|
12
10
|
# @param [Hash] mhead Message headers of a bounce email
|
|
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
|
# :received => %r/[ ][(]InterScanMSS[)][ ]with[ ]/,
|
|
18
16
|
match = 0
|
|
19
17
|
tryto = [
|
|
@@ -26,60 +24,59 @@ module Sisimai::Lhost
|
|
|
26
24
|
match += 1 if tryto.any? { |a| mhead['subject'] == a }
|
|
27
25
|
return nil unless match > 0
|
|
28
26
|
|
|
27
|
+
require 'sisimai/smtp/command'
|
|
29
28
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
30
|
-
|
|
31
|
-
bodyslices =
|
|
29
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
30
|
+
bodyslices = emailparts[0].split("\n")
|
|
32
31
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
|
33
32
|
v = nil
|
|
34
33
|
|
|
35
34
|
while e = bodyslices.shift do
|
|
36
|
-
# Read error messages and delivery status lines from the head of the email
|
|
37
|
-
#
|
|
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.
|
|
38
37
|
next if e.empty?
|
|
39
38
|
|
|
40
|
-
v
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
v = dscontents[-1]
|
|
40
|
+
p1 = e.index(' <<< ') || -1 # Sent <<< ...
|
|
41
|
+
p2 = e.index(' >>> ') || -1 # Received >>> ...
|
|
42
|
+
if e.include?('@') && e.include?(' <') && ( p1 > 1 || p2 > 1 || e.include?('Unable to deliver ') )
|
|
44
43
|
# Sent <<< RCPT TO:<kijitora@example.co.jp>
|
|
45
44
|
# Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
|
|
46
45
|
# Unable to deliver message to <kijitora@neko.example.jp>
|
|
47
|
-
|
|
46
|
+
cr = e[e.rindex('<') + 1, e.rindex('>') - e.rindex('<') - 1]
|
|
47
|
+
|
|
48
|
+
if v['recipient'] && cr != v['recipient']
|
|
48
49
|
# There are multiple recipient addresses in the message body.
|
|
49
50
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
50
51
|
v = dscontents[-1]
|
|
51
52
|
end
|
|
52
|
-
v['recipient'] =
|
|
53
|
-
v['diagnosis'] = e if e
|
|
53
|
+
v['recipient'] = cr
|
|
54
|
+
v['diagnosis'] = e if e.include?('Unable to deliver ')
|
|
54
55
|
recipients = dscontents.size
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
if
|
|
58
|
+
if e.start_with?('Sent <<< ')
|
|
58
59
|
# Sent <<< RCPT TO:<kijitora@example.co.jp>
|
|
59
|
-
v['command'] =
|
|
60
|
+
v['command'] = Sisimai::SMTP::Command.find(e)
|
|
60
61
|
|
|
61
|
-
elsif
|
|
62
|
+
elsif e.start_with?('Received >>> ')
|
|
62
63
|
# Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
|
|
63
|
-
v['diagnosis'] =
|
|
64
|
+
v['diagnosis'] = e[e.index(' >>> ') + 4, e.size]
|
|
64
65
|
else
|
|
65
66
|
# Error message in non-English
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
elsif cv = e.match(/[ ][<]{3}[ ](.+)/)
|
|
71
|
-
# <<< 550 5.1.1 User unknown
|
|
72
|
-
v['diagnosis'] = cv[1]
|
|
73
|
-
end
|
|
67
|
+
v['command'] = Sisimai::SMTP::Command.find(e) if e.include?(' >>> ')
|
|
68
|
+
p3 = e.index(' <<< ')
|
|
69
|
+
next unless p3
|
|
70
|
+
v['diagnosis'] = e[p3 + 4, e.size]
|
|
74
71
|
end
|
|
75
72
|
end
|
|
76
73
|
return nil unless recipients > 0
|
|
77
74
|
|
|
78
75
|
dscontents.each do |e|
|
|
79
76
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
80
|
-
e['reason'] = 'userunknown' if e['diagnosis']
|
|
77
|
+
e['reason'] = 'userunknown' if e['diagnosis'].include?('Unable to deliver')
|
|
81
78
|
end
|
|
82
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
|
79
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
|
83
80
|
end
|
|
84
81
|
def description; return 'Trend Micro InterScan Messaging Security Suite'; end
|
|
85
82
|
end
|