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/x3.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::X3 parses a bounce email which created by Unknown MTA #3.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::X3 parses a bounce email which created by Unknown MTA #3. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module X3
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/X3.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = { message: [' This is an automatically generated Delivery Status Notification.'] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Unknown MTA #3
|
@@ -15,20 +14,21 @@ module Sisimai::Lhost
|
|
15
14
|
# @param [String] mbody Message body of a bounce email
|
16
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
17
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
18
|
-
def
|
17
|
+
def inquire(mhead, mbody)
|
19
18
|
return nil unless mhead['subject'].start_with?('Delivery status notification')
|
20
19
|
return nil unless mhead['from'].start_with?('Mail Delivery System')
|
21
20
|
|
21
|
+
require 'sisimai/smtp/command'
|
22
22
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
23
|
-
|
24
|
-
bodyslices =
|
23
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
24
|
+
bodyslices = emailparts[0].split("\n")
|
25
25
|
readcursor = 0 # (Integer) Points the current cursor position
|
26
26
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
27
27
|
v = nil
|
28
28
|
|
29
29
|
while e = bodyslices.shift do
|
30
|
-
# Read error messages and delivery status lines from the head of the email
|
31
|
-
#
|
30
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
31
|
+
# line of the beginning of the original message.
|
32
32
|
if readcursor == 0
|
33
33
|
# Beginning of the bounce message or delivery status part
|
34
34
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -54,29 +54,29 @@ module Sisimai::Lhost
|
|
54
54
|
# ============================================================================
|
55
55
|
v = dscontents[-1]
|
56
56
|
|
57
|
-
if
|
57
|
+
if e.include?(' * ') && e.include?('@')
|
58
58
|
# * kijitora@example.com
|
59
59
|
if v['recipient']
|
60
60
|
# There are multiple recipient addresses in the message body.
|
61
61
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
62
62
|
v = dscontents[-1]
|
63
63
|
end
|
64
|
-
v['recipient'] =
|
64
|
+
v['recipient'] = e[e.index(' * ') + 3, e.size]
|
65
65
|
recipients += 1
|
66
66
|
else
|
67
67
|
# Detect error message
|
68
|
-
if
|
68
|
+
if e.start_with?('SMTP:')
|
69
69
|
# SMTP:RCPT host 192.0.2.8: 553 5.3.0 <kijitora@example.com>... No such user here
|
70
|
-
v['command'] =
|
71
|
-
v['diagnosis'] =
|
70
|
+
v['command'] = Sisimai::SMTP::Command.find(e)
|
71
|
+
v['diagnosis'] = e
|
72
72
|
|
73
|
-
elsif
|
73
|
+
elsif e.start_with?('Routing: ')
|
74
74
|
# Routing: Could not find a gateway for kijitora@example.co.jp
|
75
|
-
v['diagnosis'] =
|
75
|
+
v['diagnosis'] = e[9, e.size]
|
76
76
|
|
77
|
-
elsif
|
77
|
+
elsif e.start_with?('Diagnostic-Code: smtp; ')
|
78
78
|
# Diagnostic-Code: smtp; 552 5.2.2 Over quota
|
79
|
-
v['diagnosis'] =
|
79
|
+
v['diagnosis'] = e[e.index(';') + 2, e.size]
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
@@ -87,7 +87,7 @@ module Sisimai::Lhost
|
|
87
87
|
e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
|
88
88
|
end
|
89
89
|
|
90
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
90
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
91
91
|
end
|
92
92
|
def description; return 'Unknown MTA #3'; end
|
93
93
|
end
|
data/lib/sisimai/lhost/x4.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::X4 parses a bounce email which created by some qmail clone.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::X4 parses a bounce email which created by some qmail clone. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module X4
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/X4.pm
|
7
6
|
# MTA module for qmail clones
|
8
7
|
require 'sisimai/lhost'
|
9
8
|
|
10
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
11
|
-
|
12
|
-
StartingOf = {
|
13
|
-
MarkingsOf = {
|
10
|
+
Boundaries = ['--- Below this line is a copy of the message.', 'Original message follows.'].freeze
|
11
|
+
StartingOf = {
|
14
12
|
# qmail-remote.c:248| if (code >= 500) {
|
15
13
|
# qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
|
16
14
|
# qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
|
@@ -18,24 +16,39 @@ module Sisimai::Lhost
|
|
18
16
|
#
|
19
17
|
# Characters: K,Z,D in qmail-qmqpc.c, qmail-send.c, qmail-rspawn.c
|
20
18
|
# K = success, Z = temporary error, D = permanent error
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
19
|
+
error: ['Remote host said:'],
|
20
|
+
message: [
|
21
|
+
'He/Her is not ',
|
22
|
+
'unable to deliver your message to the following addresses',
|
23
|
+
'Su mensaje no pudo ser entregado',
|
24
|
+
'This is the machine generated message from mail service',
|
25
|
+
'This is the mail delivery agent at',
|
26
|
+
'Unable to deliver message to the following address',
|
27
|
+
'Unfortunately, your mail was not delivered to the following address:',
|
28
|
+
'Your mail message to the following address',
|
29
|
+
'Your message to the following addresses',
|
30
|
+
"We're sorry.",
|
31
|
+
],
|
32
|
+
rhost: ['Giving up on ', 'Connected to ', 'remote host '],
|
33
|
+
}.freeze
|
34
|
+
CommandSet = {
|
35
|
+
# Error text regular expressions which defined in qmail-remote.c
|
36
|
+
# qmail-remote.c:225| if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
|
37
|
+
'conn' => [' but greeting failed.'],
|
38
|
+
# qmail-remote.c:231| if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
|
39
|
+
'ehlo' => [' but my name was rejected.'],
|
40
|
+
# qmail-remote.c:238| if (code >= 500) quit("DConnected to "," but sender was rejected");
|
41
|
+
# reason = rejected
|
42
|
+
'mail' => [' but sender was rejected.'],
|
43
|
+
# qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
|
44
|
+
# qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
|
45
|
+
# reason = userunknown
|
46
|
+
'rcpt' => [' does not like recipient.'],
|
47
|
+
# qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
|
48
|
+
# qmail-remote.c:266| if (code >= 400) quit("Z"," failed on DATA command");
|
49
|
+
# qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
|
50
|
+
# qmail-remote.c:272| if (code >= 400) quit("Z"," failed after I sent the message");
|
51
|
+
'data' => [' failed on DATA command', ' failed after I sent the message'],
|
39
52
|
}.freeze
|
40
53
|
|
41
54
|
ReSMTP = {
|
@@ -61,18 +74,10 @@ module Sisimai::Lhost
|
|
61
74
|
)
|
62
75
|
}x,
|
63
76
|
}.freeze
|
64
|
-
# qmail-remote.c:261| if (!flagbother) quit("DGiving up on ","");
|
65
|
-
ReHost = %r{(?:
|
66
|
-
Giving[ ]up[ ]on[ ]([^ ]+[0-9a-zA-Z])[.]?\z
|
67
|
-
|Connected[ ]to[ ]([-0-9a-zA-Z.]+[0-9a-zA-Z])[ ]
|
68
|
-
|remote[ ]host[ ]([-0-9a-zA-Z.]+[0-9a-zA-Z])[ ]said:
|
69
|
-
)
|
70
|
-
}x
|
71
77
|
|
72
78
|
# qmail-send.c:922| ... (&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
|
73
79
|
HasExpired = 'this message has been in the queue too long.'
|
74
|
-
|
75
|
-
ReCommands = %r/Sorry, no SMTP connection got far enough; most progress was ([A-Z]{4})[ ]/
|
80
|
+
OnHoldPair = [' does not like recipient.', 'this message has been in the queue too long.'].freeze
|
76
81
|
FailOnLDAP = {
|
77
82
|
# qmail-ldap-1.03-20040101.patch:19817 - 19866
|
78
83
|
'suspend' => ['Mailaddress is administrative?le?y disabled'], # 5.2.1
|
@@ -122,30 +127,34 @@ module Sisimai::Lhost
|
|
122
127
|
# @param [String] mbody Message body of a bounce email
|
123
128
|
# @return [Hash] Bounce data list and message/rfc822 part
|
124
129
|
# @return [Nil] it failed to parse or the arguments are missing
|
125
|
-
def
|
126
|
-
# Pre process email headers and the body part of the message which generated
|
127
|
-
#
|
130
|
+
def inquire(mhead, mbody)
|
131
|
+
# Pre process email headers and the body part of the message which generated by qmail, see
|
132
|
+
# https://cr.yp.to/qmail.html
|
128
133
|
# e.g.) Received: (qmail 12345 invoked for bounce); 29 Apr 2009 12:34:56 -0000
|
129
134
|
# Subject: failure notice
|
130
|
-
tryto =
|
135
|
+
tryto = [['(qmail ', 'invoked for bounce)'], ['(qmail ', 'invoked from ', 'network)']].freeze
|
131
136
|
match = 0
|
132
137
|
match += 1 if mhead['subject'].start_with?('failure notice', 'Permanent Delivery Failure')
|
133
|
-
|
138
|
+
mhead['received'].each do |e|
|
139
|
+
# Received: (qmail 2222 invoked for bounce);29 Apr 2017 23:34:45 +0900
|
140
|
+
# Received: (qmail 2202 invoked from network); 29 Apr 2018 00:00:00 +0900
|
141
|
+
match += 1 if tryto.any? { |a| Sisimai::String.aligned(e, a) }
|
142
|
+
end
|
134
143
|
return nil unless match > 0
|
135
144
|
|
136
145
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
137
|
-
|
138
|
-
bodyslices =
|
146
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
147
|
+
bodyslices = emailparts[0].split("\n")
|
139
148
|
readcursor = 0 # (Integer) Points the current cursor position
|
140
149
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
141
150
|
v = nil
|
142
151
|
|
143
152
|
while e = bodyslices.shift do
|
144
|
-
# Read error messages and delivery status lines from the head of the email
|
145
|
-
#
|
153
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
154
|
+
# line of the beginning of the original message.
|
146
155
|
if readcursor == 0
|
147
156
|
# Beginning of the bounce message or delivery status part
|
148
|
-
readcursor |= Indicators[:deliverystatus] if
|
157
|
+
readcursor |= Indicators[:deliverystatus] if StartingOf[:message].any? { |a| e.include?(a) }
|
149
158
|
next
|
150
159
|
end
|
151
160
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
@@ -157,14 +166,14 @@ module Sisimai::Lhost
|
|
157
166
|
# Giving up on 192.0.2.153.
|
158
167
|
v = dscontents[-1]
|
159
168
|
|
160
|
-
if
|
169
|
+
if e.start_with?('<') && Sisimai::String.aligned(e, ['<', '@', '>', ':'])
|
161
170
|
# <kijitora@example.jp>:
|
162
171
|
if v['recipient']
|
163
172
|
# There are multiple recipient addresses in the message body.
|
164
173
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
165
174
|
v = dscontents[-1]
|
166
175
|
end
|
167
|
-
v['recipient'] =
|
176
|
+
v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.size])
|
168
177
|
recipients += 1
|
169
178
|
|
170
179
|
elsif dscontents.size == recipients
|
@@ -175,8 +184,15 @@ module Sisimai::Lhost
|
|
175
184
|
v['alterrors'] = e if e.start_with?(StartingOf[:error][0])
|
176
185
|
|
177
186
|
next if v['rhost']
|
178
|
-
|
179
|
-
|
187
|
+
StartingOf[:rhost].each do |r|
|
188
|
+
# Find a remote host name
|
189
|
+
p1 = e.index(r); next unless p1
|
190
|
+
cm = r.size
|
191
|
+
p2 = e.index(' ', p1 + cm + 1) || p2 = e.rindex('.')
|
192
|
+
|
193
|
+
v['rhost'] = e[p1 + cm, p2 - p1 - cm]
|
194
|
+
break
|
195
|
+
end
|
180
196
|
end
|
181
197
|
end
|
182
198
|
return nil unless recipients > 0
|
@@ -186,17 +202,16 @@ module Sisimai::Lhost
|
|
186
202
|
|
187
203
|
unless e['command']
|
188
204
|
# Get the SMTP command name for the session
|
189
|
-
|
205
|
+
CommandSet.each_key do |r|
|
190
206
|
# Verify each regular expression of SMTP commands
|
191
|
-
next unless e['diagnosis']
|
207
|
+
next unless CommandSet[r].any? { |a| e['diagnosis'].include?(a) }
|
192
208
|
e['command'] = r.upcase
|
193
209
|
break
|
194
210
|
end
|
195
211
|
|
196
|
-
|
197
|
-
#
|
198
|
-
|
199
|
-
e['command'] ||= ''
|
212
|
+
if e['diagnosis'].include?('Sorry, no SMTP connection got far enough; most progress was ')
|
213
|
+
# Get the last SMTP command:from the error message
|
214
|
+
e['command'] ||= Sisimai::SMTP::Command.find(e['diagnosis']) || ''
|
200
215
|
end
|
201
216
|
end
|
202
217
|
|
@@ -210,9 +225,8 @@ module Sisimai::Lhost
|
|
210
225
|
e['reason'] = 'blocked'
|
211
226
|
else
|
212
227
|
# Try to match with each error message in the table
|
213
|
-
if e['diagnosis']
|
214
|
-
# To decide the reason require pattern match with
|
215
|
-
# Sisimai::Reason::* modules
|
228
|
+
if Sisimai::String.aligned(e['diagnosis'], OnHoldPair)
|
229
|
+
# To decide the reason require pattern match with Sisimai::Reason::* modules
|
216
230
|
e['reason'] = 'onhold'
|
217
231
|
else
|
218
232
|
MessagesOf.each_key do |r|
|
@@ -243,9 +257,10 @@ module Sisimai::Lhost
|
|
243
257
|
end
|
244
258
|
end
|
245
259
|
end
|
260
|
+
e['command'] ||= Sisimai::SMTP::Command.find(e['diagnosis'])
|
246
261
|
end
|
247
262
|
|
248
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
263
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
249
264
|
end
|
250
265
|
def description; return 'Unknown MTA #4'; end
|
251
266
|
end
|
data/lib/sisimai/lhost/x5.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::X5 parses a bounce email which created by Unknown MTA #5.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::X5 parses a bounce email which created by Unknown MTA #5. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module X5
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/X5.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
10
|
StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Unknown MTA #5
|
@@ -15,7 +14,7 @@ module Sisimai::Lhost
|
|
15
14
|
# @param [String] mbody Message body of a bounce email
|
16
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
17
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
18
|
-
def
|
17
|
+
def inquire(mhead, mbody)
|
19
18
|
match = 0
|
20
19
|
match += 1 if mhead['to'].to_s.include?('NotificationRecipients')
|
21
20
|
if mhead['from'].include?('TWFpbCBEZWxpdmVyeSBTdWJzeXN0ZW0')
|
@@ -23,20 +22,19 @@ module Sisimai::Lhost
|
|
23
22
|
# Mail Delivery Subsystem
|
24
23
|
mhead['from'].split(' ').each do |f|
|
25
24
|
# Check each element of From: header
|
26
|
-
next unless Sisimai::
|
27
|
-
match += 1 if Sisimai::
|
25
|
+
next unless Sisimai::RFC2045.is_encoded(f)
|
26
|
+
match += 1 if Sisimai::RFC2045.decodeH([f]).include?('Mail Delivery Subsystem')
|
28
27
|
break
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
|
-
if Sisimai::
|
31
|
+
if Sisimai::RFC2045.is_encoded(mhead['subject'])
|
33
32
|
# Subject: =?iso-2022-jp?B?UmV0dXJuZWQgbWFpbDogVXNlciB1bmtub3du?=
|
34
|
-
plain = Sisimai::
|
33
|
+
plain = Sisimai::RFC2045.decodeH([mhead['subject']])
|
35
34
|
match += 1 if plain.include?('Mail Delivery Subsystem')
|
36
35
|
end
|
37
36
|
return nil if match < 2
|
38
37
|
|
39
|
-
require 'sisimai/rfc1894'
|
40
38
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
41
39
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
42
40
|
readslices = ['']
|
@@ -45,14 +43,14 @@ module Sisimai::Lhost
|
|
45
43
|
v = nil
|
46
44
|
|
47
45
|
# Pick the second message/rfc822 part because the format of email-x5-*.eml is nested structure
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
bodyslices
|
46
|
+
cutsbefore = mbody.split(Boundaries[0], 2)
|
47
|
+
cutsbefore[1] = cutsbefore[1][cutsbefore[1].index("\n\n") + 2, cutsbefore[1].size]
|
48
|
+
emailparts = Sisimai::RFC5322.part(cutsbefore[1], Boundaries)
|
49
|
+
bodyslices = emailparts[0].split("\n")
|
52
50
|
|
53
51
|
while e = bodyslices.shift do
|
54
|
-
# Read error messages and delivery status lines from the head of the email
|
55
|
-
#
|
52
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
53
|
+
# line of the beginning of the original message.
|
56
54
|
readslices << e # Save the current line for the next loop
|
57
55
|
|
58
56
|
if readcursor == 0
|
@@ -97,15 +95,15 @@ module Sisimai::Lhost
|
|
97
95
|
else
|
98
96
|
# Continued line of the value of Diagnostic-Code field
|
99
97
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
100
|
-
next unless
|
101
|
-
v['diagnosis'] << ' ' <<
|
98
|
+
next unless e.start_with?(' ')
|
99
|
+
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
102
100
|
readslices[-1] = 'Diagnostic-Code: ' << e
|
103
101
|
end
|
104
102
|
end
|
105
103
|
return nil unless recipients > 0
|
106
104
|
|
107
105
|
dscontents.each { |e| e['diagnosis'] ||= Sisimai::String.sweep(e['diagnosis']) }
|
108
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
106
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
109
107
|
end
|
110
108
|
def description; return 'Unknown MTA #5'; end
|
111
109
|
end
|
data/lib/sisimai/lhost/x6.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::X6 parses a bounce email which created by Unknown MTA #6.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::X6 parses a bounce email which created by Unknown MTA #6. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module X6
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/X6.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
11
|
-
|
9
|
+
Boundaries = ['The attachment contains the original mail headers'].freeze
|
10
|
+
StartingOf = { message: ['We had trouble delivering your message. Full details follow:'] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Unknown MTA #6
|
14
13
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -16,33 +15,41 @@ module Sisimai::Lhost
|
|
16
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
17
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
18
17
|
# @since v4.25.6
|
19
|
-
def
|
18
|
+
def inquire(mhead, mbody)
|
20
19
|
return nil unless mhead['subject'].start_with?('There was an error sending your mail')
|
21
20
|
|
22
21
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
23
|
-
|
24
|
-
bodyslices =
|
22
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
23
|
+
bodyslices = emailparts[0].split("\n")
|
25
24
|
readcursor = 0 # (Integer) Points the current cursor position
|
26
25
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
27
26
|
v = nil
|
28
27
|
|
29
28
|
while e = bodyslices.shift do
|
30
|
-
# Read error messages and delivery status lines from the head of the email
|
31
|
-
#
|
29
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
30
|
+
# line of the beginning of the original message.
|
32
31
|
if readcursor == 0
|
33
32
|
# Beginning of the bounce message or delivery status part
|
34
|
-
readcursor |= Indicators[:deliverystatus] if e
|
33
|
+
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
35
34
|
next
|
36
35
|
end
|
37
36
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
38
37
|
next if e.empty?
|
39
38
|
|
39
|
+
# We had trouble delivering your message. Full details follow:
|
40
|
+
#
|
41
|
+
# Subject: 'Nyaan'
|
42
|
+
# Date: 'Thu, 29 Apr 2012 23:34:45 +0000'
|
43
|
+
#
|
40
44
|
# 1 error(s):
|
41
45
|
#
|
42
46
|
# SMTP Server <mta2.example.jp> rejected recipient <kijitora@examplejp>
|
43
47
|
# (Error following RCPT command). It responded as follows: [550 5.1.1 User unknown]v = dscontents[-1]
|
44
|
-
v
|
45
|
-
|
48
|
+
v = dscontents[-1]
|
49
|
+
p1 = e.index('The following recipients returned permanent errors: ')
|
50
|
+
p2 = e.index('SMTP Server <')
|
51
|
+
|
52
|
+
if p1 == 0 || p2 == 0
|
46
53
|
# SMTP Server <mta2.example.jp> rejected recipient <kijitora@examplejp>
|
47
54
|
# The following recipients returned permanent errors: neko@example.jp.
|
48
55
|
if v['recipient']
|
@@ -50,22 +57,39 @@ module Sisimai::Lhost
|
|
50
57
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
51
58
|
v = dscontents[-1]
|
52
59
|
end
|
53
|
-
|
60
|
+
|
61
|
+
if p1 == 0
|
62
|
+
# The following recipients returned permanent errors: neko@example.jp.
|
63
|
+
p1 = e.index('errors: ')
|
64
|
+
p2 = e.index(' ', p1 + 8)
|
65
|
+
v['recipient'] = Sisimai::Address.s3s4(e[p1 + 8, p2 - p1 - 8])
|
66
|
+
|
67
|
+
elsif p2 == 0
|
68
|
+
# SMTP Server <mta2.example.jp> rejected recipient <kijitora@examplejp>
|
69
|
+
p1 = e.rindex('<')
|
70
|
+
p2 = e.rindex('>')
|
71
|
+
v['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
|
72
|
+
|
73
|
+
else
|
74
|
+
next
|
75
|
+
end
|
76
|
+
|
54
77
|
v['diagnosis'] = e
|
55
78
|
recipients += 1
|
56
79
|
end
|
57
80
|
end
|
58
81
|
return nil unless recipients > 0
|
59
82
|
|
83
|
+
require 'sisimai/smtp/command'
|
60
84
|
dscontents.each do |e|
|
61
|
-
if cv = e['diagnosis']
|
85
|
+
if cv = Sisimai::SMTP::Command.find(e['diagnosis'])
|
62
86
|
# ...(Error following RCPT command).
|
63
|
-
e['command'] = cv
|
87
|
+
e['command'] = cv
|
64
88
|
end
|
65
89
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
66
90
|
end
|
67
91
|
|
68
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
92
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
69
93
|
end
|
70
94
|
def description; return 'Unknown MTA #6'; end
|
71
95
|
end
|
data/lib/sisimai/lhost/yahoo.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Yahoo parses a bounce email which created by Yahoo! MAIL.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Yahoo parses a bounce email which created by Yahoo! MAIL. Methods in the module
|
3
|
+
# are called from only Sisimai::Message.
|
4
4
|
module Yahoo
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Yahoo.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
9
|
+
Boundaries = ['--- Below this line is a copy of the message.'].freeze
|
11
10
|
StartingOf = { message: ['Sorry, we were unable to deliver your message'] }.freeze
|
12
11
|
|
13
12
|
# Parse bounce messages from Yahoo! MAIL
|
@@ -15,23 +14,24 @@ module Sisimai::Lhost
|
|
15
14
|
# @param [String] mbody Message body of a bounce email
|
16
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
17
16
|
# @return [Nil] it failed to parse or the arguments are missing
|
18
|
-
def
|
17
|
+
def inquire(mhead, mbody)
|
19
18
|
# X-YMailISG: YtyUVyYWLDsbDh...
|
20
19
|
# X-YMail-JAS: Pb65aU4VM1mei...
|
21
20
|
# X-YMail-OSG: bTIbpDEVM1lHz...
|
22
21
|
# X-Originating-IP: [192.0.2.9]
|
23
22
|
return nil unless mhead['x-ymailisg']
|
24
23
|
|
24
|
+
require 'sisimai/smtp/command'
|
25
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
26
|
-
|
27
|
-
bodyslices =
|
26
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
+
bodyslices = emailparts[0].split("\n")
|
28
28
|
readcursor = 0 # (Integer) Points the current cursor position
|
29
29
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
30
30
|
v = nil
|
31
31
|
|
32
32
|
while e = bodyslices.shift do
|
33
|
-
# Read error messages and delivery status lines from the head of the email
|
34
|
-
#
|
33
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
34
|
+
# line of the beginning of the original message.
|
35
35
|
if readcursor == 0
|
36
36
|
# Beginning of the bounce message or delivery status part
|
37
37
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
@@ -46,23 +46,24 @@ module Sisimai::Lhost
|
|
46
46
|
# Remote host said: 550 5.1.1 <kijitora@example.org>... User Unknown [RCPT_TO]
|
47
47
|
v = dscontents[-1]
|
48
48
|
|
49
|
-
if
|
49
|
+
if e.start_with?('<') && Sisimai::String.aligned(e, ['<', '@', '>:'])
|
50
50
|
# <kijitora@example.org>:
|
51
51
|
if v['recipient']
|
52
52
|
# There are multiple recipient addresses in the message body.
|
53
53
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
54
54
|
v = dscontents[-1]
|
55
55
|
end
|
56
|
-
v['recipient'] =
|
56
|
+
v['recipient'] = Sisimai::Address.s3s4(e[0, e.index('>:')])
|
57
57
|
v['diagnosis'] = ''
|
58
58
|
recipients += 1
|
59
|
+
|
59
60
|
else
|
60
61
|
if e.start_with?('Remote host said:')
|
61
62
|
# Remote host said: 550 5.1.1 <kijitora@example.org>... User Unknown [RCPT_TO]
|
62
63
|
v['diagnosis'] = e
|
63
64
|
|
64
65
|
# Get SMTP command from the value of "Remote host said:"
|
65
|
-
|
66
|
+
v['command'] = Sisimai::SMTP::Command.find(e)
|
66
67
|
else
|
67
68
|
# <mailboxfull@example.jp>:
|
68
69
|
# Remote host said:
|
@@ -71,9 +72,9 @@ module Sisimai::Lhost
|
|
71
72
|
if v['diagnosis'].start_with?('Remote host said:')
|
72
73
|
# Remote host said:
|
73
74
|
# 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full
|
74
|
-
if cv =
|
75
|
+
if cv = Sisimai::SMTP::Command.find(e)
|
75
76
|
# [RCPT_TO]
|
76
|
-
v['command'] = cv
|
77
|
+
v['command'] = cv
|
77
78
|
else
|
78
79
|
# 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full
|
79
80
|
v['diagnosis'] = e
|
@@ -89,10 +90,10 @@ module Sisimai::Lhost
|
|
89
90
|
|
90
91
|
dscontents.each do |e|
|
91
92
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].gsub(/\\n/, ' '))
|
92
|
-
e['command'] ||= 'RCPT' if e['diagnosis']
|
93
|
+
e['command'] ||= 'RCPT' if Sisimai::String.aligned(e['diagnosis'], ['<', '@', '>'])
|
93
94
|
end
|
94
95
|
|
95
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
96
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
96
97
|
end
|
97
98
|
def description; return 'Yahoo! MAIL: https://www.yahoo.com'; end
|
98
99
|
end
|