sisimai 4.25.15-java → 5.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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 +419 -388
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +140 -78
- data/README.md +290 -143
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +23 -18
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -313
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -47
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +12 -12
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +42 -22
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
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
|