sisimai 5.4.1-java → 5.6.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 +4 -4
- data/.github/workflows/codecovio.yml +1 -1
- data/.github/workflows/rake-test.yml +1 -1
- data/ChangeLog.md +56 -0
- data/LICENSE +1 -1
- data/Makefile +2 -4
- data/README-JA.md +29 -23
- data/README.md +30 -24
- data/lib/sisimai/address.rb +92 -44
- data/lib/sisimai/arf.rb +7 -8
- data/lib/sisimai/datetime.rb +2 -2
- data/lib/sisimai/fact/json.rb +1 -2
- data/lib/sisimai/fact/yaml.rb +1 -2
- data/lib/sisimai/fact.rb +76 -36
- data/lib/sisimai/lda.rb +2 -2
- data/lib/sisimai/lhost/activehunter.rb +4 -5
- data/lib/sisimai/lhost/amazonses.rb +4 -5
- data/lib/sisimai/lhost/apachejames.rb +2 -2
- data/lib/sisimai/lhost/biglobe.rb +6 -6
- data/lib/sisimai/lhost/courier.rb +7 -7
- data/lib/sisimai/lhost/domino.rb +6 -6
- data/lib/sisimai/lhost/dragonfly.rb +5 -5
- data/lib/sisimai/lhost/einsundeins.rb +5 -5
- data/lib/sisimai/lhost/exchange2003.rb +7 -7
- data/lib/sisimai/lhost/exchange2007.rb +5 -5
- data/lib/sisimai/lhost/exim.rb +13 -15
- data/lib/sisimai/lhost/ezweb.rb +3 -2
- data/lib/sisimai/lhost/fml.rb +9 -9
- data/lib/sisimai/lhost/gmail.rb +9 -9
- data/lib/sisimai/lhost/gmx.rb +3 -3
- data/lib/sisimai/lhost/googlegroups.rb +6 -7
- data/lib/sisimai/lhost/googleworkspace.rb +5 -6
- data/lib/sisimai/lhost/imailserver.rb +4 -4
- data/lib/sisimai/lhost/kddi.rb +4 -4
- data/lib/sisimai/lhost/mailfoundry.rb +3 -3
- data/lib/sisimai/lhost/{mailmarshalsmtp.rb → mailmarshal.rb} +5 -5
- data/lib/sisimai/lhost/messagingserver.rb +8 -8
- data/lib/sisimai/lhost/mfilter.rb +8 -4
- data/lib/sisimai/lhost/mimecast.rb +105 -0
- data/lib/sisimai/lhost/notes.rb +5 -5
- data/lib/sisimai/lhost/opensmtpd.rb +5 -5
- data/lib/sisimai/lhost/postfix.rb +38 -32
- data/lib/sisimai/lhost/qmail.rb +11 -11
- data/lib/sisimai/lhost/sendmail.rb +13 -13
- data/lib/sisimai/lhost/{interscanmss.rb → trendmicro.rb} +8 -9
- data/lib/sisimai/lhost/v5sendmail.rb +7 -7
- data/lib/sisimai/lhost/verizon.rb +3 -3
- data/lib/sisimai/lhost/x1.rb +7 -4
- data/lib/sisimai/lhost/x2.rb +40 -12
- data/lib/sisimai/lhost/x3.rb +3 -3
- data/lib/sisimai/lhost/x6.rb +2 -2
- data/lib/sisimai/lhost/zoho.rb +5 -5
- data/lib/sisimai/lhost.rb +18 -17
- data/lib/sisimai/mail/maildir.rb +4 -4
- data/lib/sisimai/mail/mbox.rb +4 -4
- data/lib/sisimai/mail/memory.rb +1 -1
- data/lib/sisimai/mail/stdin.rb +2 -2
- data/lib/sisimai/message.rb +36 -34
- data/lib/sisimai/order.rb +5 -4
- data/lib/sisimai/reason/authfailure.rb +10 -14
- data/lib/sisimai/reason/badreputation.rb +8 -8
- data/lib/sisimai/reason/blocked.rb +58 -83
- data/lib/sisimai/reason/contenterror.rb +15 -10
- data/lib/sisimai/reason/{mesgtoobig.rb → emailtoolarge.rb} +23 -26
- data/lib/sisimai/reason/expired.rb +17 -24
- data/lib/sisimai/reason/failedstarttls.rb +1 -1
- data/lib/sisimai/reason/filtered.rb +14 -18
- data/lib/sisimai/reason/hasmoved.rb +3 -2
- data/lib/sisimai/reason/hostunknown.rb +18 -21
- data/lib/sisimai/reason/mailboxfull.rb +28 -50
- data/lib/sisimai/reason/mailererror.rb +1 -1
- data/lib/sisimai/reason/networkerror.rb +17 -17
- data/lib/sisimai/reason/norelaying.rb +20 -20
- data/lib/sisimai/reason/notaccept.rb +7 -10
- data/lib/sisimai/reason/notcompliantrfc.rb +6 -10
- data/lib/sisimai/reason/policyviolation.rb +12 -28
- data/lib/sisimai/reason/ratelimited.rb +62 -0
- data/lib/sisimai/reason/rejected.rb +46 -58
- data/lib/sisimai/reason/requireptr.rb +14 -26
- data/lib/sisimai/reason/securityerror.rb +14 -20
- data/lib/sisimai/reason/spamdetected.rb +52 -102
- data/lib/sisimai/reason/suspend.rb +27 -24
- data/lib/sisimai/reason/systemerror.rb +20 -24
- data/lib/sisimai/reason/systemfull.rb +2 -2
- data/lib/sisimai/reason/userunknown.rb +82 -114
- data/lib/sisimai/reason/vacation.rb +1 -1
- data/lib/sisimai/reason/virusdetected.rb +7 -9
- data/lib/sisimai/reason.rb +26 -26
- data/lib/sisimai/rfc1123.rb +58 -18
- data/lib/sisimai/rfc1894.rb +6 -8
- data/lib/sisimai/rfc2045.rb +25 -13
- data/lib/sisimai/rfc3464/thirdparty.rb +2 -3
- data/lib/sisimai/rfc3464.rb +6 -6
- data/lib/sisimai/rfc3834.rb +18 -8
- data/lib/sisimai/rfc5322.rb +9 -9
- data/lib/sisimai/rfc791.rb +2 -2
- data/lib/sisimai/rhost/aol.rb +4 -1
- data/lib/sisimai/rhost/apple.rb +15 -11
- data/lib/sisimai/rhost/cloudflare.rb +2 -0
- data/lib/sisimai/rhost/cox.rb +31 -25
- data/lib/sisimai/rhost/facebook.rb +24 -18
- data/lib/sisimai/rhost/franceptt.rb +92 -38
- data/lib/sisimai/rhost/godaddy.rb +34 -7
- data/lib/sisimai/rhost/google.rb +69 -70
- data/lib/sisimai/rhost/gsuite.rb +1 -1
- data/lib/sisimai/rhost/iua.rb +1 -1
- data/lib/sisimai/rhost/kddi.rb +1 -1
- data/lib/sisimai/rhost/messagelabs.rb +160 -2
- data/lib/sisimai/rhost/microsoft.rb +154 -107
- data/lib/sisimai/rhost/mimecast.rb +64 -55
- data/lib/sisimai/rhost/nttdocomo.rb +70 -90
- data/lib/sisimai/rhost/outlook.rb +1 -1
- data/lib/sisimai/rhost/spectrum.rb +8 -8
- data/lib/sisimai/rhost/tencent.rb +12 -13
- data/lib/sisimai/rhost/yahooinc.rb +9 -10
- data/lib/sisimai/rhost/zoho.rb +72 -0
- data/lib/sisimai/rhost.rb +4 -3
- data/lib/sisimai/smtp/command.rb +4 -2
- data/lib/sisimai/smtp/reply.rb +11 -4
- data/lib/sisimai/smtp/status.rb +67 -98
- data/lib/sisimai/smtp/transcript.rb +3 -3
- data/lib/sisimai/string.rb +4 -23
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +1 -1
- data/set-of-emails/maildir/bsd/lhost-exim-56.eml +40 -40
- data/set-of-emails/maildir/bsd/lhost-mfilter-05.eml +41 -0
- data/set-of-emails/maildir/bsd/lhost-mimecast-01.eml +46 -0
- data/set-of-emails/maildir/bsd/lhost-mimecast-02.eml +59 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-79.eml +81 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-80.eml +84 -0
- data/set-of-emails/maildir/bsd/lhost-x1-03.eml +26 -0
- data/set-of-emails/maildir/bsd/lhost-x1-04.eml +45 -0
- data/set-of-emails/maildir/bsd/lhost-x2-07.eml +30 -0
- data/set-of-emails/maildir/bsd/rfc3464-66.eml +170 -0
- data/set-of-emails/maildir/bsd/rfc3834-06.eml +59 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-01.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-02.eml +86 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-03.eml +87 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-04.eml +86 -0
- data/set-of-emails/maildir/not/rb-issue-368-bug.eml +39 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +28 -13
- data/lib/sisimai/reason/exceedlimit.rb +0 -47
- data/lib/sisimai/reason/speeding.rb +0 -47
- data/lib/sisimai/reason/toomanyconn.rb +0 -59
- /data/set-of-emails/maildir/bsd/{lhost-mailmarshalsmtp-02.eml → lhost-mailmarshal-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-interscanmss-01.eml → lhost-trendmicro-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-interscanmss-02.eml → lhost-trendmicro-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-interscanmss-03.eml → lhost-trendmicro-03.eml} +0 -0
|
@@ -36,10 +36,10 @@ module Sisimai::Lhost
|
|
|
36
36
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
37
37
|
def inquire(mhead, mbody)
|
|
38
38
|
# :from => %r/\AMail Delivery Subsystem/,
|
|
39
|
-
return nil
|
|
39
|
+
return nil if mhead['subject'].start_with?('Returned mail: ') == false
|
|
40
40
|
|
|
41
41
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
42
|
-
return nil
|
|
42
|
+
return nil if emailparts[1].size == 0
|
|
43
43
|
|
|
44
44
|
require 'sisimai/rfc1123'
|
|
45
45
|
require 'sisimai/smtp/command'
|
|
@@ -133,7 +133,7 @@ module Sisimai::Lhost
|
|
|
133
133
|
# There is no recipient address in the error message
|
|
134
134
|
anotherone.each_key do |e|
|
|
135
135
|
# Try to pick an recipient address, a reply code, and error messages
|
|
136
|
-
cv = Sisimai::Address.s3s4(anotherone[e]); next
|
|
136
|
+
cv = Sisimai::Address.s3s4(anotherone[e]); next if Sisimai::Address.is_emailaddress(cv) == false
|
|
137
137
|
cr = Sisimai::SMTP::Reply.find(anotherone[e])
|
|
138
138
|
|
|
139
139
|
dscontents[e]["recipient"] = cv
|
|
@@ -150,13 +150,13 @@ module Sisimai::Lhost
|
|
|
150
150
|
if p1 > 0
|
|
151
151
|
# Get the recipient address from "To:" header at the original message
|
|
152
152
|
cv = Sisimai::Address.s3s4(emailparts[1][p1, p2 - p1 - 5])
|
|
153
|
-
return nil
|
|
153
|
+
return nil if Sisimai::Address.is_emailaddress(cv) == false
|
|
154
154
|
dscontents[0]["recipient"] = cv
|
|
155
155
|
recipients += 1
|
|
156
156
|
end
|
|
157
157
|
end
|
|
158
158
|
end
|
|
159
|
-
return nil
|
|
159
|
+
return nil if recipients == 0
|
|
160
160
|
|
|
161
161
|
j = 0; dscontents.each do |e|
|
|
162
162
|
# Tidy up the error message in e.Diagnosis
|
|
@@ -169,8 +169,8 @@ module Sisimai::Lhost
|
|
|
169
169
|
# @example.jp, no local part
|
|
170
170
|
# Get email address from the value of Diagnostic-Code header
|
|
171
171
|
next if e['recipient'].include?('@')
|
|
172
|
-
p1 = e['diagnosis'].index('<'); next
|
|
173
|
-
p2 = e['diagnosis'].index('>'); next
|
|
172
|
+
p1 = e['diagnosis'].index('<'); next if p1.nil?
|
|
173
|
+
p2 = e['diagnosis'].index('>'); next if p2.nil?
|
|
174
174
|
e['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
|
|
175
175
|
end
|
|
176
176
|
|
|
@@ -16,7 +16,7 @@ module Sisimai::Lhost
|
|
|
16
16
|
while true
|
|
17
17
|
# Check the value of "From" header
|
|
18
18
|
# :'subject' => %r/Undeliverable Message/,
|
|
19
|
-
break
|
|
19
|
+
break if mhead['received'].none? { |a| a.include?('.vtext.com (') }
|
|
20
20
|
match = 1 if mhead['from'] == 'post_master@vtext.com'
|
|
21
21
|
match = 0 if Sisimai::String.aligned(mhead['from'], ['sysadmin@', '.vzwpix.com'])
|
|
22
22
|
break
|
|
@@ -130,7 +130,7 @@ module Sisimai::Lhost
|
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
|
-
return nil
|
|
133
|
+
return nil if recipients == 0
|
|
134
134
|
|
|
135
135
|
# Set the value of "MAIL FROM:" and "From:"
|
|
136
136
|
emailparts[1] += "From: #{senderaddr}\n" if emailparts[1].include?("\nFrom: ") == false
|
|
@@ -140,7 +140,7 @@ module Sisimai::Lhost
|
|
|
140
140
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
141
141
|
messagesof.each_key do |r|
|
|
142
142
|
# Verify each regular expression of session errors
|
|
143
|
-
next
|
|
143
|
+
next if messagesof[r].none? { |a| e['diagnosis'].include?(a) }
|
|
144
144
|
e['reason'] = r
|
|
145
145
|
break
|
|
146
146
|
end
|
data/lib/sisimai/lhost/x1.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Sisimai::Lhost
|
|
|
6
6
|
require 'sisimai/lhost'
|
|
7
7
|
|
|
8
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
9
|
-
Boundaries = ['Received: from '].freeze
|
|
9
|
+
Boundaries = ['Content-Type: message/rfc822', 'Received: from '].freeze
|
|
10
10
|
MarkingsOf = {message: ['The original message was received at ']}.freeze
|
|
11
11
|
|
|
12
12
|
# @abstract Decodes the bounce message from Unknown MTA #1
|
|
@@ -15,8 +15,11 @@ module Sisimai::Lhost
|
|
|
15
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
16
16
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
17
17
|
def inquire(mhead, mbody)
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
proceedsto = false
|
|
19
|
+
proceedsto = true if mhead['subject'].start_with?('Returned Mail: ')
|
|
20
|
+
proceedsto = true if mhead['subject'].start_with?('Mail Delivery Failure')
|
|
21
|
+
proceedsto = true if Sisimai::String.aligned(mhead['from'], ['"Mail Deliver', 'System" '])
|
|
22
|
+
return nil if proceedsto == false
|
|
20
23
|
|
|
21
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
22
25
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -61,7 +64,7 @@ module Sisimai::Lhost
|
|
|
61
64
|
datestring = e[MarkingsOf[:message][0].size, e.size]
|
|
62
65
|
end
|
|
63
66
|
end
|
|
64
|
-
return nil
|
|
67
|
+
return nil if recipients == 0
|
|
65
68
|
|
|
66
69
|
dscontents.each do |e|
|
|
67
70
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
data/lib/sisimai/lhost/x2.rb
CHANGED
|
@@ -7,7 +7,11 @@ module Sisimai::Lhost
|
|
|
7
7
|
|
|
8
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
|
9
9
|
Boundaries = ['--- Original message follows.'].freeze
|
|
10
|
-
StartingOf = {
|
|
10
|
+
StartingOf = {
|
|
11
|
+
message: [
|
|
12
|
+
"Unable to deliver message to the following address",
|
|
13
|
+
"This Delivery Status Notification is sent from MTA",
|
|
14
|
+
]}.freeze
|
|
11
15
|
|
|
12
16
|
# @abstract Decodes the bounce message from Unknown MTA #2
|
|
13
17
|
# @param [Hash] mhead Message headers of a bounce email
|
|
@@ -15,12 +19,12 @@ module Sisimai::Lhost
|
|
|
15
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
16
20
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
17
21
|
def inquire(mhead, mbody)
|
|
18
|
-
match =
|
|
19
|
-
match ||=
|
|
20
|
-
match ||=
|
|
21
|
-
match ||=
|
|
22
|
-
match ||=
|
|
23
|
-
return nil
|
|
22
|
+
match = false
|
|
23
|
+
match ||= true if mhead['from'].include?('MAILER-DAEMON@')
|
|
24
|
+
match ||= true if mhead['subject'].start_with?('Delivery failure')
|
|
25
|
+
match ||= true if mhead['subject'].start_with?('failure delivery')
|
|
26
|
+
match ||= true if mhead['subject'].start_with?('failed delivery')
|
|
27
|
+
return nil if match == false
|
|
24
28
|
|
|
25
29
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
26
30
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -33,7 +37,7 @@ module Sisimai::Lhost
|
|
|
33
37
|
# line of the beginning of the original message.
|
|
34
38
|
if readcursor == 0
|
|
35
39
|
# Beginning of the bounce message or delivery status part
|
|
36
|
-
readcursor |= Indicators[:deliverystatus] if e.start_with?(
|
|
40
|
+
readcursor |= Indicators[:deliverystatus] if StartingOf[:message].any? { |a| e.start_with?(a) }
|
|
37
41
|
next
|
|
38
42
|
end
|
|
39
43
|
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
|
@@ -43,23 +47,47 @@ module Sisimai::Lhost
|
|
|
43
47
|
#
|
|
44
48
|
# <kijitora@example.com>:
|
|
45
49
|
# This user doesn't have a example.com account (kijitora@example.com) [0]
|
|
50
|
+
#
|
|
51
|
+
# --- OR ---
|
|
52
|
+
#
|
|
53
|
+
# This Delivery Status Notification is sent from MTA...
|
|
54
|
+
#
|
|
55
|
+
# Your delivery to the following address has been failed.
|
|
56
|
+
# Please refer to the below for details.
|
|
57
|
+
# ------------------------------------------------------
|
|
58
|
+
#
|
|
59
|
+
# Delivery failed: kijitora@example.co.jp
|
|
60
|
+
# 192.0.2.25 does not like recipient.
|
|
61
|
+
# Remote host said[Response Message]: 550 5.1.1 <kijitora@example.co.jp>:
|
|
62
|
+
# Recipient address rejected: User unknown in local recipient table
|
|
63
|
+
# Giving up on 192.0.2.25.
|
|
64
|
+
# STEP: RCPT TO
|
|
46
65
|
v = dscontents[-1]
|
|
47
66
|
|
|
48
|
-
if e.start_with?('<')
|
|
67
|
+
if e.start_with?('<') && Sisimai::String.aligned(e, ['<', '@', '>:']) ||
|
|
68
|
+
e.start_with?('Delivery failed: ') && Sisimai::String.aligned(e, ['failed: ', '@'])
|
|
49
69
|
# <kijitora@example.com>:
|
|
70
|
+
# Delivery failed: kijitora@example.co.jp
|
|
50
71
|
if v["recipient"] != ""
|
|
51
72
|
# There are multiple recipient addresses in the message body.
|
|
52
73
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
|
53
74
|
v = dscontents[-1]
|
|
54
75
|
end
|
|
55
|
-
v['recipient'] = e[1, e.size - 3]
|
|
76
|
+
v['recipient'] = e[1, e.size - 3] if e.start_with?('<')
|
|
77
|
+
v['recipient'] = e[e.index(': ') + 2, e.size - 1] if v['recipient'].empty?
|
|
56
78
|
recipients += 1
|
|
57
|
-
|
|
79
|
+
|
|
80
|
+
elsif e.start_with?('STEP: ')
|
|
81
|
+
# STEP: RCPT TO
|
|
82
|
+
# STEP: DATA SEND
|
|
83
|
+
v['command'] = Sisimai::SMTP::Command.find(e)
|
|
84
|
+
|
|
85
|
+
elsif e.start_with?('-----') == false
|
|
58
86
|
# This user doesn't have a example.com account (kijitora@example.com) [0]
|
|
59
87
|
v['diagnosis'] += " #{e}"
|
|
60
88
|
end
|
|
61
89
|
end
|
|
62
|
-
return nil
|
|
90
|
+
return nil if recipients == 0
|
|
63
91
|
|
|
64
92
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
|
65
93
|
return {"ds" => dscontents, "rfc822" => emailparts[1]}
|
data/lib/sisimai/lhost/x3.rb
CHANGED
|
@@ -15,8 +15,8 @@ module Sisimai::Lhost
|
|
|
15
15
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
16
16
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
17
17
|
def inquire(mhead, mbody)
|
|
18
|
-
return nil
|
|
19
|
-
return nil
|
|
18
|
+
return nil if mhead['subject'].start_with?('Delivery status notification') == false
|
|
19
|
+
return nil if mhead['from'].start_with?('Mail Delivery System') == false
|
|
20
20
|
|
|
21
21
|
require 'sisimai/smtp/command'
|
|
22
22
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
|
@@ -79,7 +79,7 @@ module Sisimai::Lhost
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
|
-
return nil
|
|
82
|
+
return nil if recipients == 0
|
|
83
83
|
|
|
84
84
|
dscontents.each do |e|
|
|
85
85
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
data/lib/sisimai/lhost/x6.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Sisimai::Lhost
|
|
|
16
16
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
17
17
|
# @since v4.25.6
|
|
18
18
|
def inquire(mhead, mbody)
|
|
19
|
-
return nil
|
|
19
|
+
return nil if mhead['subject'].start_with?('There was an error sending your mail') == false
|
|
20
20
|
|
|
21
21
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
22
22
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -76,7 +76,7 @@ module Sisimai::Lhost
|
|
|
76
76
|
recipients += 1
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
|
-
return nil
|
|
79
|
+
return nil if recipients == 0
|
|
80
80
|
|
|
81
81
|
require 'sisimai/smtp/command'
|
|
82
82
|
dscontents.each do |e|
|
data/lib/sisimai/lhost/zoho.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Sisimai::Lhost
|
|
|
19
19
|
# X-ZohoMail: Si CHF_MF_NL SS_10 UW48 UB48 FMWL UW48 UB48 SGR3_1_09124_42
|
|
20
20
|
# X-Zoho-Virus-Status: 2
|
|
21
21
|
# X-Mailer: Zoho Mail
|
|
22
|
-
return nil
|
|
22
|
+
return nil if mhead['x-zohomail'].nil?
|
|
23
23
|
|
|
24
24
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
25
25
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -68,7 +68,7 @@ module Sisimai::Lhost
|
|
|
68
68
|
end
|
|
69
69
|
recipients += 1
|
|
70
70
|
|
|
71
|
-
elsif e.start_with?('[Status: ')
|
|
71
|
+
elsif e.start_with?('[Status: ') && e.include?('<') && e.include?('>')
|
|
72
72
|
# Expired
|
|
73
73
|
# [Status: Error, Address: <kijitora@6kaku.example.co.jp>, ResponseCode 421, , Host not reachable.]
|
|
74
74
|
if v["recipient"] != ""
|
|
@@ -83,17 +83,17 @@ module Sisimai::Lhost
|
|
|
83
83
|
recipients += 1
|
|
84
84
|
else
|
|
85
85
|
# Continued line
|
|
86
|
-
next
|
|
86
|
+
next if qprintable == false
|
|
87
87
|
v['diagnosis'] += e
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
-
return nil
|
|
90
|
+
return nil if recipients == 0
|
|
91
91
|
|
|
92
92
|
dscontents.each do |e|
|
|
93
93
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].tr("\n", ' '))
|
|
94
94
|
MessagesOf.each_key do |r|
|
|
95
95
|
# Verify each regular expression of session errors
|
|
96
|
-
next
|
|
96
|
+
next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
|
|
97
97
|
e['reason'] = r
|
|
98
98
|
break
|
|
99
99
|
end
|
data/lib/sisimai/lhost.rb
CHANGED
|
@@ -9,20 +9,21 @@ module Sisimai
|
|
|
9
9
|
# @private
|
|
10
10
|
def DELIVERYSTATUS
|
|
11
11
|
return {
|
|
12
|
-
'spec' => "",
|
|
13
|
-
'date' => "",
|
|
14
|
-
'rhost' => "",
|
|
15
|
-
'lhost' => "",
|
|
16
|
-
'alias' => "",
|
|
17
|
-
'agent' => "",
|
|
18
|
-
'action' => "",
|
|
19
|
-
'status' => "",
|
|
20
|
-
'reason' => "",
|
|
21
|
-
'command' => "",
|
|
22
|
-
'replycode' => "",
|
|
23
|
-
'diagnosis' => "",
|
|
24
|
-
'recipient' => "",
|
|
25
|
-
'feedbacktype' => "",
|
|
12
|
+
'spec' => "", # Protocl specification
|
|
13
|
+
'date' => "", # The value of Last-Attempt-Date header
|
|
14
|
+
'rhost' => "", # The value of Remote-MTA header
|
|
15
|
+
'lhost' => "", # The value of Received-From-MTA header
|
|
16
|
+
'alias' => "", # The value of alias entry(RHS)
|
|
17
|
+
'agent' => "", # MTA module name
|
|
18
|
+
'action' => "", # The value of Action header
|
|
19
|
+
'status' => "", # The value of Status header
|
|
20
|
+
'reason' => "", # Temporary reason of bounce
|
|
21
|
+
'command' => "", # SMTP command in the message body
|
|
22
|
+
'replycode' => "", # SMTP Reply code
|
|
23
|
+
'diagnosis' => "", # The value of Diagnostic-Code header
|
|
24
|
+
'recipient' => "", # The value of Final-Recipient header
|
|
25
|
+
'feedbacktype' => "", # Feedback Type
|
|
26
|
+
'toxic' => false, # EXPERIMENTAL
|
|
26
27
|
}
|
|
27
28
|
end
|
|
28
29
|
|
|
@@ -41,9 +42,9 @@ module Sisimai
|
|
|
41
42
|
def index
|
|
42
43
|
return %w[
|
|
43
44
|
Activehunter AmazonSES ApacheJames Biglobe Courier Domino DragonFly EZweb EinsUndEins Exchange2003
|
|
44
|
-
Exchange2007 Exim FML GMX GoogleWorkspace GoogleGroups Gmail IMailServer
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
Exchange2007 Exim FML GMX GoogleWorkspace GoogleGroups Gmail IMailServer KDDI MailFoundry Mimecast
|
|
46
|
+
MailMarshal MessagingServer Notes OpenSMTPD Postfix Sendmail TrendMicro V5sendmail Verizon
|
|
47
|
+
X1 X2 X3 X6 Zoho MFILTER Qmail
|
|
47
48
|
]
|
|
48
49
|
end
|
|
49
50
|
|
data/lib/sisimai/mail/maildir.rb
CHANGED
|
@@ -16,8 +16,8 @@ module Sisimai
|
|
|
16
16
|
# @return [Sisimai::Mail::Maildir] Object
|
|
17
17
|
# [Nil] is not a directory or does not exist
|
|
18
18
|
def initialize(argv1)
|
|
19
|
-
raise Errno::ENOENT
|
|
20
|
-
raise Errno::ENOTDIR
|
|
19
|
+
raise Errno::ENOENT if File.exist?(argv1) == false
|
|
20
|
+
raise Errno::ENOTDIR if File.ftype(argv1) != 'directory'
|
|
21
21
|
|
|
22
22
|
@path = nil
|
|
23
23
|
@size = Dir.entries(argv1).size
|
|
@@ -30,7 +30,7 @@ module Sisimai
|
|
|
30
30
|
# Maildir reader, works as an iterator.
|
|
31
31
|
# @return [String] Contents of file in Maildir/
|
|
32
32
|
def read
|
|
33
|
-
return nil
|
|
33
|
+
return nil if self.offset >= self.size
|
|
34
34
|
seekhandle = self.handle
|
|
35
35
|
readbuffer = ''
|
|
36
36
|
|
|
@@ -61,7 +61,7 @@ module Sisimai
|
|
|
61
61
|
self.file = r
|
|
62
62
|
break
|
|
63
63
|
end
|
|
64
|
-
seekhandle.close
|
|
64
|
+
seekhandle.close if self.offset >= self.size
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
return readbuffer
|
data/lib/sisimai/mail/mbox.rb
CHANGED
|
@@ -16,8 +16,8 @@ module Sisimai
|
|
|
16
16
|
# @return [Sisimai::Mail::Mbox] Object
|
|
17
17
|
# [Nil] is not specified or does not exist
|
|
18
18
|
def initialize(argv1)
|
|
19
|
-
raise Errno::ENOENT
|
|
20
|
-
raise 'is not a file'
|
|
19
|
+
raise Errno::ENOENT if File.exist?(argv1) == false
|
|
20
|
+
raise 'is not a file' if File.ftype(argv1) != 'file'
|
|
21
21
|
|
|
22
22
|
@path = argv1
|
|
23
23
|
@dir = File.dirname(argv1)
|
|
@@ -30,7 +30,7 @@ module Sisimai
|
|
|
30
30
|
# Mbox reader, works as an iterator.
|
|
31
31
|
# @return [String] Contents of mbox
|
|
32
32
|
def read
|
|
33
|
-
return nil
|
|
33
|
+
return nil if self.offset >= self.size
|
|
34
34
|
|
|
35
35
|
seekoffset = self.offset || 0
|
|
36
36
|
filehandle = self.handle
|
|
@@ -53,7 +53,7 @@ module Sisimai
|
|
|
53
53
|
seekoffset = filehandle.pos - frombuffer.bytesize
|
|
54
54
|
frombuffer = ''
|
|
55
55
|
self.offset = seekoffset
|
|
56
|
-
filehandle.close
|
|
56
|
+
filehandle.close if self.offset >= self.size
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
return readbuffer.to_s
|
data/lib/sisimai/mail/memory.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Sisimai
|
|
|
14
14
|
# @return [Sisimai::Mail::Memory] Object
|
|
15
15
|
# [Nil] is not specified or does not exist
|
|
16
16
|
def initialize(argv1)
|
|
17
|
-
raise 'is not a String'
|
|
17
|
+
raise 'is not a String' if argv1.is_a?(::String) == false
|
|
18
18
|
raise 'is empty' if argv1.empty?
|
|
19
19
|
|
|
20
20
|
@path = '<MEMORY>'
|
data/lib/sisimai/mail/stdin.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Sisimai
|
|
|
13
13
|
# @param [IO::STDIN] stdin Standard-In
|
|
14
14
|
# @return [Sisimai::Mail::STDIN] Object
|
|
15
15
|
def initialize(stdin = $stdin)
|
|
16
|
-
raise 'is not an IO object'
|
|
16
|
+
raise 'is not an IO object' if stdin.is_a?(IO) == false
|
|
17
17
|
|
|
18
18
|
@path = '<STDIN>'
|
|
19
19
|
@size = nil
|
|
@@ -32,7 +32,7 @@ module Sisimai
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
begin
|
|
35
|
-
readhandle = STDIN
|
|
35
|
+
readhandle = STDIN if readhandle.nil?
|
|
36
36
|
while r = readhandle.gets
|
|
37
37
|
break if readbuffer.size > 0 && r.start_with?('From ')
|
|
38
38
|
readbuffer << r
|
data/lib/sisimai/message.rb
CHANGED
|
@@ -21,12 +21,15 @@ module Sisimai
|
|
|
21
21
|
FieldIndex = [Fields1894.flatten, Fields5322.flatten, Fields5965.flatten].flatten.freeze
|
|
22
22
|
FieldTable = FieldIndex.map { |e| [e.downcase, e] }.to_h.freeze
|
|
23
23
|
Boundaries = ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'].freeze
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]
|
|
29
|
-
|
|
24
|
+
MediaTypes = [
|
|
25
|
+
%w[message/xdelivery-status message/delivery-status],
|
|
26
|
+
%w[message/disposition-notification message/delivery-status],
|
|
27
|
+
%w[message/global-delivery-status message/delivery-status],
|
|
28
|
+
%w[message/global-disposition-notification message/delivery-status],
|
|
29
|
+
%w[message/global-delivery-status message/delivery-status],
|
|
30
|
+
%w[message/global-headers text/rfc822-headers],
|
|
31
|
+
%w[message/global message/rfc822],
|
|
32
|
+
].freeze
|
|
30
33
|
|
|
31
34
|
# Read an email message and convert to structured format
|
|
32
35
|
# @param [Hash] argvs Module to be loaded
|
|
@@ -35,7 +38,7 @@ module Sisimai
|
|
|
35
38
|
# @return [Sisimai::Message] Structured email data or nil if each
|
|
36
39
|
# value of the arguments are missing
|
|
37
40
|
def rise(**argvs)
|
|
38
|
-
return nil
|
|
41
|
+
return nil if argvs.nil?
|
|
39
42
|
email = argvs[:data].scrub('?').gsub("\r\n", "\n")
|
|
40
43
|
thing = {'from' => '','header' => {}, 'rfc822' => '', 'ds' => [], 'catch' => nil}
|
|
41
44
|
param = {}
|
|
@@ -53,12 +56,12 @@ module Sisimai
|
|
|
53
56
|
thing['header'] = Sisimai::Message.makemap(aftersplit[1])
|
|
54
57
|
|
|
55
58
|
# 3. Decode and rewrite the "Subject:" header
|
|
56
|
-
|
|
59
|
+
if thing['header']['subject'].empty? == false
|
|
57
60
|
# Decode MIME-Encoded "Subject:" header
|
|
58
61
|
cv = thing['header']['subject']
|
|
59
62
|
cq = Sisimai::RFC2045.is_encoded(cv) ? Sisimai::RFC2045.decodeH(cv.split(/[ ]/)) : cv
|
|
60
63
|
cl = cq.downcase
|
|
61
|
-
p1 = cl.index('fwd:'); p1 = cl.index('fw:')
|
|
64
|
+
p1 = cl.index('fwd:'); p1 = cl.index('fw:') if p1.nil?
|
|
62
65
|
|
|
63
66
|
# Remove "Fwd:" string from the Subject: header
|
|
64
67
|
if p1
|
|
@@ -77,17 +80,16 @@ module Sisimai
|
|
|
77
80
|
'tryonfirst' => Sisimai::Order.make(thing['header']['subject'])
|
|
78
81
|
}
|
|
79
82
|
break if beforefact = Sisimai::Message.sift(param)
|
|
80
|
-
break
|
|
83
|
+
break if Boundaries.none? { |a| aftersplit[2].include?(a) }
|
|
81
84
|
|
|
82
85
|
# 5. Try to sift again
|
|
83
86
|
# There is a bounce message inside of mutipart/*, try to sift the first message/rfc822
|
|
84
87
|
# part as a entire message body again.
|
|
85
88
|
parseagain += 1
|
|
86
89
|
email = Sisimai::RFC5322.part(aftersplit[2], Boundaries, true).pop.sub(/\A\s+/, '')
|
|
87
|
-
break
|
|
90
|
+
break if email.size < 128
|
|
88
91
|
end
|
|
89
|
-
return nil
|
|
90
|
-
return nil if beforefact.empty?
|
|
92
|
+
return nil if beforefact.nil? || beforefact.empty?
|
|
91
93
|
|
|
92
94
|
# 6. Rewrite headers of the original message in the body part
|
|
93
95
|
%w|ds catch rfc822|.each { |e| thing[e] = beforefact[e] }
|
|
@@ -109,8 +111,7 @@ module Sisimai
|
|
|
109
111
|
email.gsub!(/\r\n/, "\n") if email.include?("\r\n")
|
|
110
112
|
|
|
111
113
|
(parts[1], parts[2]) = email.split(/\n\n/, 2)
|
|
112
|
-
return nil
|
|
113
|
-
return nil unless parts[2]
|
|
114
|
+
return nil if parts[1].nil? || parts[2].nil?
|
|
114
115
|
|
|
115
116
|
if parts[1].start_with?('From ')
|
|
116
117
|
# From MAILER-DAEMON Tue Feb 11 00:00:00 2014
|
|
@@ -119,7 +120,7 @@ module Sisimai
|
|
|
119
120
|
# Set pseudo UNIX From line
|
|
120
121
|
parts[0] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
|
|
121
122
|
end
|
|
122
|
-
parts[1] += "\n"
|
|
123
|
+
parts[1] += "\n" if parts[1].end_with?("\n") == false
|
|
123
124
|
|
|
124
125
|
%w[image/ application/ text/html].each do |e|
|
|
125
126
|
# https://github.com/sisimai/p5-sisimai/issues/492, Reduce email size
|
|
@@ -128,8 +129,8 @@ module Sisimai
|
|
|
128
129
|
ep = e == 'text/html' ? '</html>' : "--\n"
|
|
129
130
|
while true
|
|
130
131
|
# Remove each part from "Content-Type: image/..." to "--\n" (the end of each boundary)
|
|
131
|
-
p0 = parts[2].index("Content-Type: #{e}", p0); break
|
|
132
|
-
p1 = parts[2].index(ep, p0 + 32); break
|
|
132
|
+
p0 = parts[2].index("Content-Type: #{e}", p0); break if p0.nil?
|
|
133
|
+
p1 = parts[2].index(ep, p0 + 32); break if p1.nil?
|
|
133
134
|
parts[2][p0, p1 - p0] = ''
|
|
134
135
|
end
|
|
135
136
|
end
|
|
@@ -170,8 +171,7 @@ module Sisimai
|
|
|
170
171
|
end
|
|
171
172
|
headermaps['received'] = receivedby
|
|
172
173
|
|
|
173
|
-
return headermaps
|
|
174
|
-
return headermaps if headermaps['subject'].empty?
|
|
174
|
+
return headermaps if argv1.nil? || headermaps['subject'].empty?
|
|
175
175
|
|
|
176
176
|
# Convert MIME-Encoded subject
|
|
177
177
|
if Sisimai::String.is_8bit(headermaps['subject'])
|
|
@@ -209,7 +209,7 @@ module Sisimai
|
|
|
209
209
|
# Find and tidy up fields defined in RFC5322, RFC1894, and RFC5965
|
|
210
210
|
# 1. Find a field label defined in RFC5322, RFC1894, or RFC5965 from this line
|
|
211
211
|
p0 = e.index(':') || -1
|
|
212
|
-
cf = e.downcase[0, p0]
|
|
212
|
+
cf = e.downcase[0, p0].to_s.rstrip
|
|
213
213
|
fn = FieldTable[cf] || ''
|
|
214
214
|
|
|
215
215
|
index += 1
|
|
@@ -227,7 +227,7 @@ module Sisimai
|
|
|
227
227
|
# Such as Diagnostic-Code, Remote-MTA, and so on
|
|
228
228
|
# - Before: Diagnostic-Code: SMTP;550 User unknown
|
|
229
229
|
# - After: Diagnostic-Code: smtp; 550 User unknown
|
|
230
|
-
break
|
|
230
|
+
break if ['Content-Type'].concat(Fields1894).none? { |a| a == fn }
|
|
231
231
|
|
|
232
232
|
if p1
|
|
233
233
|
# The field including one or more ";"
|
|
@@ -251,7 +251,8 @@ module Sisimai
|
|
|
251
251
|
ps = f[0, p2].downcase
|
|
252
252
|
f[0, p2] = ps
|
|
253
253
|
end
|
|
254
|
-
f.downcase!
|
|
254
|
+
f.downcase! if ps != 'boundary'
|
|
255
|
+
f = 'rfc822' if f == 'rfc/822'
|
|
255
256
|
break
|
|
256
257
|
end
|
|
257
258
|
ab << f
|
|
@@ -261,9 +262,9 @@ module Sisimai
|
|
|
261
262
|
# Diagnostic-Code: x-unix;
|
|
262
263
|
# /var/email/kijitora/Maildir/tmp/1000000000.A000000B00000.neko22:
|
|
263
264
|
# Disk quota exceeded
|
|
264
|
-
break
|
|
265
|
-
break
|
|
266
|
-
break
|
|
265
|
+
break if fn != 'Diagnostic-Code'
|
|
266
|
+
break if ab.size != 1
|
|
267
|
+
break if lines[index + 1].start_with?(' ') == false
|
|
267
268
|
|
|
268
269
|
ab << ''
|
|
269
270
|
break
|
|
@@ -281,9 +282,9 @@ module Sisimai
|
|
|
281
282
|
end
|
|
282
283
|
|
|
283
284
|
# 3. Tidy up a value, and a parameter of Content-Type: field
|
|
284
|
-
if
|
|
285
|
+
if fn == "Content-Type"
|
|
285
286
|
# Replace the value of "Content-Type" field
|
|
286
|
-
|
|
287
|
+
MediaTypes.each do |f|
|
|
287
288
|
# - Before: Content-Type: message/xdelivery-status; ...
|
|
288
289
|
# - After: Content-Type: message/delivery-status; ...
|
|
289
290
|
p1 = bf.index(f[0]) || next
|
|
@@ -296,7 +297,9 @@ module Sisimai
|
|
|
296
297
|
email += sprintf("%s: %s\n", fn, bf)
|
|
297
298
|
end
|
|
298
299
|
|
|
299
|
-
|
|
300
|
+
# 5. Convert the lower-cased SMTP command to the upper-cased.
|
|
301
|
+
email = email.gsub("after end of data:", "after end of DATA:")
|
|
302
|
+
email += "\n" if email.end_with?("\n\n") == false
|
|
300
303
|
return email
|
|
301
304
|
end
|
|
302
305
|
|
|
@@ -311,14 +314,13 @@ module Sisimai
|
|
|
311
314
|
# @param options argvs [Array] tryonfirst MTA module list to load on first
|
|
312
315
|
# @return [Hash] Decoded and structured bounce mails
|
|
313
316
|
def sift(argvs)
|
|
314
|
-
return nil
|
|
315
|
-
return nil unless argvs['body']
|
|
317
|
+
return nil if argvs['mail'].nil? || argvs['body'].nil?
|
|
316
318
|
|
|
317
319
|
mailheader = argvs['mail']['header']
|
|
318
320
|
bodystring = argvs['body']
|
|
319
321
|
hookmethod = argvs['hook'] || nil
|
|
320
322
|
havecaught = nil
|
|
321
|
-
return nil
|
|
323
|
+
return nil if mailheader.nil?
|
|
322
324
|
|
|
323
325
|
# PRECHECK_EACH_HEADER:
|
|
324
326
|
# Set empty string if the value is nil
|
|
@@ -351,7 +353,7 @@ module Sisimai
|
|
|
351
353
|
# NOT text/plain
|
|
352
354
|
# In case of Content-Type: multipart/*
|
|
353
355
|
p = Sisimai::RFC2045.makeflat(mailheader['content-type'], bodystring)
|
|
354
|
-
bodystring = p
|
|
356
|
+
bodystring = p if p.empty? == false
|
|
355
357
|
end
|
|
356
358
|
bodystring = bodystring.scrub('?').delete("\r").gsub("\t", " ")
|
|
357
359
|
|
|
@@ -412,7 +414,7 @@ module Sisimai
|
|
|
412
414
|
break # as of now, we have no sample email for coding this block
|
|
413
415
|
end
|
|
414
416
|
end
|
|
415
|
-
return nil
|
|
417
|
+
return nil if havesifted.nil?
|
|
416
418
|
|
|
417
419
|
havesifted['catch'] = havecaught
|
|
418
420
|
modulename = modulename.sub(/\A.+::/, '')
|