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/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
|