sisimai 4.25.17-java → 5.0.0-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/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +406 -407
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +12 -12
- data/README-JA.md +142 -94
- data/README.md +282 -150
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +20 -16
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -325
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -45
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +13 -18
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +42 -23
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
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,14 @@ 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", ' ');
|
52
51
|
recordwide['diagnosis'] = Sisimai::String.sweep(entiremesg)
|
53
|
-
recordwide['reason'] =
|
52
|
+
recordwide['reason'] = emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4 ? 'rejected' : 'onhold'
|
54
53
|
recordwide['rhost'] = Sisimai::RFC5322.received(mhead['received'][0]).shift
|
55
54
|
|
56
55
|
mhead['x-failed-recipients'].split(',').each do |e|
|
57
56
|
# X-Failed-Recipients: neko@example.jp, nyaan@example.org, ...
|
58
|
-
next unless Sisimai::
|
57
|
+
next unless Sisimai::Address.is_emailaddress(e)
|
59
58
|
|
60
59
|
if v['recipient']
|
61
60
|
# There are multiple recipient addresses in the message body.
|
@@ -67,7 +66,7 @@ module Sisimai::Lhost
|
|
67
66
|
recordwide.each_key { |r| v[r] = recordwide[r] }
|
68
67
|
end
|
69
68
|
return nil unless recipients > 0
|
70
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
69
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
71
70
|
end
|
72
71
|
def description; return 'Google Groups: https://groups.google.com'; end
|
73
72
|
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
|
@@ -148,7 +142,7 @@ module Sisimai::Lhost
|
|
148
142
|
# Copy alternative error message
|
149
143
|
e['diagnosis'] = anotherset['diagnosis'] unless e['diagnosis']
|
150
144
|
|
151
|
-
if e['diagnosis']
|
145
|
+
if e['diagnosis'].include?(' ') == false && e['diagnosis'].to_i > 0
|
152
146
|
e['diagnosis'] = anotherset['diagnosis']
|
153
147
|
else
|
154
148
|
# More detailed error message is in "anotherset"
|
@@ -192,7 +186,7 @@ module Sisimai::Lhost
|
|
192
186
|
end
|
193
187
|
end
|
194
188
|
|
195
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
189
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
196
190
|
end
|
197
191
|
def description; return 'G Suite: https://gsuite.google.com'; end
|
198
192
|
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
|
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
|