sisimai 5.4.1-java → 5.5.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 +35 -0
- data/Makefile +2 -4
- data/README-JA.md +23 -20
- data/README.md +23 -20
- 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 +60 -35
- data/lib/sisimai/lda.rb +2 -2
- data/lib/sisimai/lhost/activehunter.rb +4 -5
- data/lib/sisimai/lhost/amazonses.rb +3 -4
- 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 +4 -4
- data/lib/sisimai/lhost/exchange2003.rb +7 -7
- data/lib/sisimai/lhost/exchange2007.rb +3 -3
- data/lib/sisimai/lhost/exim.rb +7 -7
- 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 +6 -6
- 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 +34 -34
- data/lib/sisimai/order.rb +5 -4
- data/lib/sisimai/reason/authfailure.rb +1 -1
- data/lib/sisimai/reason/badreputation.rb +1 -1
- data/lib/sisimai/reason/blocked.rb +2 -1
- data/lib/sisimai/reason/contenterror.rb +1 -2
- data/lib/sisimai/reason/exceedlimit.rb +1 -1
- data/lib/sisimai/reason/expired.rb +1 -1
- data/lib/sisimai/reason/failedstarttls.rb +1 -1
- data/lib/sisimai/reason/filtered.rb +1 -1
- data/lib/sisimai/reason/hasmoved.rb +1 -1
- data/lib/sisimai/reason/hostunknown.rb +2 -2
- data/lib/sisimai/reason/mailboxfull.rb +1 -1
- data/lib/sisimai/reason/mailererror.rb +1 -1
- data/lib/sisimai/reason/mesgtoobig.rb +1 -1
- data/lib/sisimai/reason/networkerror.rb +1 -1
- data/lib/sisimai/reason/norelaying.rb +2 -2
- data/lib/sisimai/reason/notaccept.rb +2 -3
- data/lib/sisimai/reason/notcompliantrfc.rb +1 -1
- data/lib/sisimai/reason/policyviolation.rb +2 -4
- data/lib/sisimai/reason/rejected.rb +5 -3
- data/lib/sisimai/reason/requireptr.rb +1 -1
- data/lib/sisimai/reason/securityerror.rb +1 -1
- data/lib/sisimai/reason/spamdetected.rb +1 -1
- data/lib/sisimai/reason/speeding.rb +1 -1
- data/lib/sisimai/reason/suspend.rb +2 -1
- data/lib/sisimai/reason/systemerror.rb +1 -1
- data/lib/sisimai/reason/systemfull.rb +1 -1
- data/lib/sisimai/reason/toomanyconn.rb +1 -1
- data/lib/sisimai/reason/userunknown.rb +4 -3
- data/lib/sisimai/reason/vacation.rb +1 -1
- data/lib/sisimai/reason/virusdetected.rb +1 -1
- data/lib/sisimai/reason.rb +12 -12
- 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 +11 -7
- data/lib/sisimai/rhost/cox.rb +9 -5
- data/lib/sisimai/rhost/facebook.rb +9 -3
- data/lib/sisimai/rhost/franceptt.rb +86 -37
- data/lib/sisimai/rhost/godaddy.rb +10 -1
- data/lib/sisimai/rhost/google.rb +6 -6
- data/lib/sisimai/rhost/gsuite.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 +77 -26
- data/lib/sisimai/rhost/mimecast.rb +30 -21
- data/lib/sisimai/rhost/nttdocomo.rb +69 -89
- data/lib/sisimai/rhost/outlook.rb +1 -1
- data/lib/sisimai/rhost/spectrum.rb +1 -1
- data/lib/sisimai/rhost/tencent.rb +5 -4
- data/lib/sisimai/rhost/yahooinc.rb +2 -2
- data/lib/sisimai/rhost/zoho.rb +72 -0
- data/lib/sisimai/rhost.rb +4 -3
- data/lib/sisimai/smtp/command.rb +2 -2
- data/lib/sisimai/smtp/reply.rb +11 -4
- data/lib/sisimai/smtp/status.rb +17 -8
- data/lib/sisimai/smtp/transcript.rb +3 -3
- data/lib/sisimai/string.rb +6 -10
- 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 +26 -9
- /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
|
@@ -19,7 +19,6 @@ module Sisimai
|
|
|
19
19
|
Index = [
|
|
20
20
|
'an illegal attachment on your message',
|
|
21
21
|
'because the recipient is not accepting mail with ', # AOL Phoenix
|
|
22
|
-
'by non-member to a members-only list',
|
|
23
22
|
'closed mailing list',
|
|
24
23
|
'denied by policy',
|
|
25
24
|
'email not accepted for policy reasons',
|
|
@@ -35,9 +34,8 @@ module Sisimai
|
|
|
35
34
|
'messages with multiple addresses',
|
|
36
35
|
'rejected for policy reasons',
|
|
37
36
|
'protocol violation',
|
|
38
|
-
'the email address used to send your message is not subscribed to this group',
|
|
39
37
|
'the message was rejected by organization policy',
|
|
40
|
-
'this message was blocked because its content presents a potential',
|
|
38
|
+
'this message was blocked because its content presents a potential', # https://support.google.com/mail/answer/6590
|
|
41
39
|
'we do not accept messages containing images or other attachments',
|
|
42
40
|
"you're using a mass mailer",
|
|
43
41
|
].freeze
|
|
@@ -53,7 +51,7 @@ module Sisimai
|
|
|
53
51
|
# @return [Boolean] false: Did not match, true: Matched
|
|
54
52
|
# @since 4.22.0
|
|
55
53
|
def match(argv1)
|
|
56
|
-
return false
|
|
54
|
+
return false if argv1.nil? || argv1.empty?
|
|
57
55
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
58
56
|
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
59
57
|
return false
|
|
@@ -23,11 +23,12 @@ module Sisimai
|
|
|
23
23
|
'access denied (sender blacklisted)',
|
|
24
24
|
'address rejected',
|
|
25
25
|
'administrative prohibition',
|
|
26
|
-
'batv failed to verify', #
|
|
27
|
-
'batv validation failure', #
|
|
26
|
+
'batv failed to verify', # SonicWall
|
|
27
|
+
'batv validation failure', # SonicWall
|
|
28
28
|
'backscatter protection detected an invalid or expired email address', # MDaemon
|
|
29
29
|
"because the sender isn't on the recipient's list of senders to accept mail from",
|
|
30
30
|
'bogus mail from', # IMail - block empty sender
|
|
31
|
+
'by non-member to a members-only list',
|
|
31
32
|
"can't determine purported responsible address",
|
|
32
33
|
'connections not accepted from servers without a valid sender domain',
|
|
33
34
|
'denied [bouncedeny]', # McAfee
|
|
@@ -66,6 +67,7 @@ module Sisimai
|
|
|
66
67
|
'sender was rejected', # qmail
|
|
67
68
|
'spam reporting address', # SendGrid|a message to an address has previously been marked as Spam by the recipient.
|
|
68
69
|
'syntax error: empty email address',
|
|
70
|
+
'the email address used to send your message is not subscribed to this group',
|
|
69
71
|
'the message has been rejected by batv defense',
|
|
70
72
|
'this server does not accept mail from',
|
|
71
73
|
'transaction failed unsigned dsn for',
|
|
@@ -83,7 +85,7 @@ module Sisimai
|
|
|
83
85
|
# @param [String] argv1 String to be matched with regular expressions
|
|
84
86
|
# @return [Boolean] false: Did not match, true: Matched
|
|
85
87
|
def match(argv1)
|
|
86
|
-
return false
|
|
88
|
+
return false if argv1.nil? || argv1.empty?
|
|
87
89
|
return false if IsNot.any? { |a| argv1.include?(a) }
|
|
88
90
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
89
91
|
return false
|
|
@@ -44,7 +44,7 @@ module Sisimai
|
|
|
44
44
|
# @param [String] argv1 String to be matched with regular expressions
|
|
45
45
|
# @return [Boolean] false: Did not match, true: Matched
|
|
46
46
|
def match(argv1)
|
|
47
|
-
return false
|
|
47
|
+
return false if argv1.nil? || argv1.empty?
|
|
48
48
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
49
49
|
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
50
50
|
return false
|
|
@@ -48,7 +48,7 @@ module Sisimai
|
|
|
48
48
|
# @param [String] argv1 String to be matched with regular expressions
|
|
49
49
|
# @return [Boolean] false: Did not match, true: Matched
|
|
50
50
|
def match(argv1)
|
|
51
|
-
return false
|
|
51
|
+
return false if argv1.nil? || argv1.empty?
|
|
52
52
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
53
53
|
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
54
54
|
return false
|
|
@@ -122,7 +122,7 @@ module Sisimai
|
|
|
122
122
|
# @param [String] argv1 String to be matched with regular expressions
|
|
123
123
|
# @return [Boolean] false: Did not match, true: Matched
|
|
124
124
|
def match(argv1)
|
|
125
|
-
return false
|
|
125
|
+
return false if argv1.nil? || argv1.empty?
|
|
126
126
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
127
127
|
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
128
128
|
return false
|
|
@@ -18,7 +18,7 @@ module Sisimai
|
|
|
18
18
|
# @param [String] argv1 String to be matched with regular expressions
|
|
19
19
|
# @return [Boolean] false: Did not match, true: Matched
|
|
20
20
|
def match(argv1)
|
|
21
|
-
return false
|
|
21
|
+
return false if argv1.nil? || argv1.empty?
|
|
22
22
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
23
23
|
return false
|
|
24
24
|
end
|
|
@@ -22,6 +22,7 @@ module Sisimai
|
|
|
22
22
|
'mailbox unavailable or access denied',
|
|
23
23
|
'recipient rejected: temporarily inactive',
|
|
24
24
|
'recipient suspend the service',
|
|
25
|
+
"the email account that you tried to reach is inactive",
|
|
25
26
|
'this account has been disabled or discontinued',
|
|
26
27
|
'this account has been temporarily suspended',
|
|
27
28
|
'this address no longer accepts mail',
|
|
@@ -38,7 +39,7 @@ module Sisimai
|
|
|
38
39
|
# @param [String] argv1 String to be matched with regular expressions
|
|
39
40
|
# @return [Boolean] false: Did not match, true: Matched
|
|
40
41
|
def match(argv1)
|
|
41
|
-
return false
|
|
42
|
+
return false if argv1.nil? || argv1.empty?
|
|
42
43
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
43
44
|
return false
|
|
44
45
|
end
|
|
@@ -45,7 +45,7 @@ module Sisimai
|
|
|
45
45
|
# @param [String] argv1 String to be matched with regular expressions
|
|
46
46
|
# @return [Boolean] false: Did not match, true: Matched
|
|
47
47
|
def match(argv1)
|
|
48
|
-
return false
|
|
48
|
+
return false if argv1.nil? || argv1.empty?
|
|
49
49
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
50
50
|
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
51
51
|
return false
|
|
@@ -20,7 +20,7 @@ module Sisimai
|
|
|
20
20
|
# @param [String] argv1 String to be matched with regular expressions
|
|
21
21
|
# @return [Boolean] false: Did not match, true: Matched
|
|
22
22
|
def match(argv1)
|
|
23
|
-
return false
|
|
23
|
+
return false if argv1.nil? || argv1.empty?
|
|
24
24
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
25
25
|
return false
|
|
26
26
|
end
|
|
@@ -34,7 +34,7 @@ module Sisimai
|
|
|
34
34
|
# @param [String] argv1 String to be matched with regular expressions
|
|
35
35
|
# @return [Boolean] false: Did not match, true: Matched
|
|
36
36
|
def match(argv1)
|
|
37
|
-
return false
|
|
37
|
+
return false if argv1.nil? || argv1.empty?
|
|
38
38
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
39
39
|
return false
|
|
40
40
|
end
|
|
@@ -112,6 +112,7 @@ module Sisimai
|
|
|
112
112
|
'user unknown',
|
|
113
113
|
'utilisateur inconnu !',
|
|
114
114
|
'vdeliver: invalid or unknown virtual user',
|
|
115
|
+
'weil die adresse nicht gefunden wurde oder keine e-mails empfangen kann',
|
|
115
116
|
'your envelope recipient is in my badrcptto list',
|
|
116
117
|
].freeze
|
|
117
118
|
Pairs = [
|
|
@@ -147,7 +148,7 @@ module Sisimai
|
|
|
147
148
|
# @param [String] argv1 String to be matched with regular expressions
|
|
148
149
|
# @return [Boolean] false: Did not match, true: Matched
|
|
149
150
|
def match(argv1)
|
|
150
|
-
return false
|
|
151
|
+
return false if argv1.nil? || argv1.empty?
|
|
151
152
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
152
153
|
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
153
154
|
return false
|
|
@@ -183,12 +184,12 @@ module Sisimai
|
|
|
183
184
|
next
|
|
184
185
|
end
|
|
185
186
|
|
|
186
|
-
next
|
|
187
|
+
next if r.match(issuedcode) == false
|
|
187
188
|
# Match with reason defined in Sisimai::Reason::* except UserUnknown.
|
|
188
189
|
matchother = true
|
|
189
190
|
break
|
|
190
191
|
end
|
|
191
|
-
return true
|
|
192
|
+
return true if matchother == false # Did not match with other message patterns
|
|
192
193
|
|
|
193
194
|
elsif argvs['command'] == 'RCPT'
|
|
194
195
|
# When the SMTP command is not "RCPT", the session rejected by other
|
|
@@ -18,7 +18,7 @@ module Sisimai
|
|
|
18
18
|
# @param [String] argv1 String to be matched with regular expressions
|
|
19
19
|
# @return [Boolean] false: Did not match, true: Matched
|
|
20
20
|
def match(argv1)
|
|
21
|
-
return false
|
|
21
|
+
return false if argv1.nil? || argv1.empty?
|
|
22
22
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
23
23
|
return false
|
|
24
24
|
end
|
|
@@ -31,7 +31,7 @@ module Sisimai
|
|
|
31
31
|
# @return [Boolean] false: Did not match, true: Matched
|
|
32
32
|
# @since 4.22.0
|
|
33
33
|
def match(argv1)
|
|
34
|
-
return false
|
|
34
|
+
return false if argv1.nil? || argv1.empty?
|
|
35
35
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
36
36
|
return false
|
|
37
37
|
end
|
data/lib/sisimai/reason.rb
CHANGED
|
@@ -68,11 +68,11 @@ module Sisimai
|
|
|
68
68
|
# @return [String] Bounce reason or an empty string if the argument is missing or not Hash
|
|
69
69
|
# @see anotherone
|
|
70
70
|
def find(argvs)
|
|
71
|
-
return ""
|
|
72
|
-
|
|
71
|
+
return "" if argvs.nil?
|
|
72
|
+
if GetRetried[argvs['reason']].nil?
|
|
73
73
|
# Return reason text already decided except reason match with the regular expression of
|
|
74
74
|
# retry() method.
|
|
75
|
-
return argvs['reason']
|
|
75
|
+
return argvs['reason'] if argvs['reason'].empty? == false
|
|
76
76
|
end
|
|
77
77
|
return 'delivered' if argvs['deliverystatus'].start_with?('2.')
|
|
78
78
|
|
|
@@ -94,7 +94,7 @@ module Sisimai
|
|
|
94
94
|
warn " ***warning: Failed to load #{p}"
|
|
95
95
|
next
|
|
96
96
|
end
|
|
97
|
-
next
|
|
97
|
+
next if r.true(argvs) == false
|
|
98
98
|
reasontext = r.text
|
|
99
99
|
break
|
|
100
100
|
end
|
|
@@ -113,7 +113,7 @@ module Sisimai
|
|
|
113
113
|
# Try to match with message patterns in Sisimai::Reason::Vacation
|
|
114
114
|
require 'sisimai/reason/vacation'
|
|
115
115
|
reasontext = 'vacation' if Sisimai::Reason::Vacation.match(issuedcode.downcase)
|
|
116
|
-
reasontext ||= 'onhold'
|
|
116
|
+
reasontext ||= 'onhold' if issuedcode.empty? == false
|
|
117
117
|
reasontext ||= 'undefined'
|
|
118
118
|
end
|
|
119
119
|
end
|
|
@@ -125,7 +125,7 @@ module Sisimai
|
|
|
125
125
|
# @return [String, Nil] Bounce reason or nli if the argument is missing or not Hash
|
|
126
126
|
# @see find()
|
|
127
127
|
def anotherone(argvs)
|
|
128
|
-
return argvs['reason']
|
|
128
|
+
return argvs['reason'] if argvs['reason'].empty? == false
|
|
129
129
|
|
|
130
130
|
require 'sisimai/smtp/status'
|
|
131
131
|
issuedcode = argvs['diagnosticcode'].downcase || ''
|
|
@@ -150,11 +150,11 @@ module Sisimai
|
|
|
150
150
|
next
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
-
next
|
|
153
|
+
next if r.match(issuedcode) == false
|
|
154
154
|
reasontext = e.downcase
|
|
155
155
|
break
|
|
156
156
|
end
|
|
157
|
-
break
|
|
157
|
+
break if reasontext.empty? == false
|
|
158
158
|
|
|
159
159
|
# Check the value of Status:
|
|
160
160
|
code2digit = statuscode[0, 3] || ''
|
|
@@ -175,7 +175,7 @@ module Sisimai
|
|
|
175
175
|
require 'sisimai/reason/syntaxerror'
|
|
176
176
|
reasontext = 'syntaxerror' if Sisimai::Reason::SyntaxError.true(argvs)
|
|
177
177
|
end
|
|
178
|
-
break
|
|
178
|
+
break if reasontext.empty? == false
|
|
179
179
|
|
|
180
180
|
# Check the value of Action: field, first
|
|
181
181
|
if actiontext.start_with?('delayed', 'expired')
|
|
@@ -195,7 +195,7 @@ module Sisimai
|
|
|
195
195
|
# @param [String] argv1 Error message
|
|
196
196
|
# @return [String] Bounce reason
|
|
197
197
|
def match(argv1)
|
|
198
|
-
return ""
|
|
198
|
+
return "" if argv1.nil?
|
|
199
199
|
|
|
200
200
|
reasontext = ''
|
|
201
201
|
issuedcode = argv1.downcase
|
|
@@ -214,11 +214,11 @@ module Sisimai
|
|
|
214
214
|
next
|
|
215
215
|
end
|
|
216
216
|
|
|
217
|
-
next
|
|
217
|
+
next if r.match(issuedcode) == false
|
|
218
218
|
reasontext = r.text
|
|
219
219
|
break
|
|
220
220
|
end
|
|
221
|
-
return reasontext
|
|
221
|
+
return reasontext if reasontext.empty? == false
|
|
222
222
|
|
|
223
223
|
if issuedcode.upcase.include?('X-UNIX; ')
|
|
224
224
|
# X-Unix; ...
|
data/lib/sisimai/rfc1123.rb
CHANGED
|
@@ -3,6 +3,7 @@ module Sisimai
|
|
|
3
3
|
module RFC1123
|
|
4
4
|
class << self
|
|
5
5
|
require 'sisimai/string'
|
|
6
|
+
require 'sisimai/rfc791'
|
|
6
7
|
Sandwiched = [
|
|
7
8
|
# (Postfix) postfix/src/smtp/smtp_proto.c: "host %s said: %s (in reply to %s)",
|
|
8
9
|
# - <kijitora@example.com>: host re2.example.com[198.51.100.2] said: 550 ...
|
|
@@ -37,32 +38,72 @@ module Sisimai
|
|
|
37
38
|
# @return [Boolean] false: is not a valid internet host, true: is a valid interneet host
|
|
38
39
|
# @since v5.2.0
|
|
39
40
|
def is_internethost(argv0 = '')
|
|
40
|
-
return false
|
|
41
|
-
return
|
|
41
|
+
return false if argv0.nil? || argv0.size < 4 || argv0.size > 255
|
|
42
|
+
return true if argv0 == 'localhost' || argv0 == 'localhost6'
|
|
42
43
|
return false if argv0.include?(".") == false
|
|
43
44
|
return false if argv0.include?("..") || argv0.include?("--")
|
|
44
45
|
return false if argv0.start_with?(".", "-") || argv0.end_with?("-")
|
|
45
46
|
|
|
46
|
-
hostnameok = true
|
|
47
47
|
characters = argv0.upcase.split("")
|
|
48
48
|
characters.each do |e|
|
|
49
49
|
# Check each characater is a number or an alphabet
|
|
50
50
|
f = e.ord
|
|
51
|
-
if f < 45
|
|
52
|
-
if f == 47
|
|
53
|
-
if f > 57 && f < 65
|
|
54
|
-
if f > 90
|
|
51
|
+
return false if f < 45 # 45 = '-'
|
|
52
|
+
return false if f == 47 # 47 = '/'
|
|
53
|
+
return false if f > 57 && f < 65 # 57 = '9', 65 = 'A'
|
|
54
|
+
return false if f > 90 # 90 = 'Z'
|
|
55
55
|
end
|
|
56
|
-
return false if hostnameok == false
|
|
57
56
|
|
|
58
57
|
p1 = argv0.rindex(".")
|
|
59
58
|
cv = argv0[p1 + 1, argv0.size - p1]; return false if cv.size > 63
|
|
60
59
|
cv.split("").each do |e|
|
|
61
60
|
# The top level domain should not include a number
|
|
62
|
-
f = e.ord
|
|
63
|
-
if f > 47 && f < 58 then hostnameok = false; break; end
|
|
61
|
+
f = e.ord; return false if f > 47 && f < 58
|
|
64
62
|
end
|
|
65
|
-
return
|
|
63
|
+
return true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# returns true if the domain part is [IPv4:...] or [IPv6:...].
|
|
67
|
+
# @param [String] email Email address.
|
|
68
|
+
# @return [Boolean] false: the domain part is not a domain literal.
|
|
69
|
+
# true: the domain part is a domain literal.
|
|
70
|
+
def is_domainliteral(email)
|
|
71
|
+
return false if email.is_a?(::String) == false
|
|
72
|
+
|
|
73
|
+
email = email.delete_prefix('<').delete_suffix('>')
|
|
74
|
+
return false if email.size < 16 # e@[IPv4:0.0.0.0] is 16 characters
|
|
75
|
+
return false if email[-1, 1] != ']'
|
|
76
|
+
|
|
77
|
+
lastb = email.rindex('@[IPv'); return false if lastb == false
|
|
78
|
+
dpart = email.split('@')[-1]
|
|
79
|
+
|
|
80
|
+
if email.include?('@[IPv4:')
|
|
81
|
+
# neko@[IPv4:192.0.2.25]
|
|
82
|
+
ipv4a = email[lastb + 7, 16].delete_suffix(']')
|
|
83
|
+
return Sisimai::RFC791.is_ipv4address(ipv4a)
|
|
84
|
+
|
|
85
|
+
elsif email.include?('@[IPv6:')
|
|
86
|
+
# neko@[IPv6:2001:0DB8:0000:0000:0000:0000:0000:0001]
|
|
87
|
+
# neko@[IPv6:2001:0DB8:0000:0000:0000:0000:0000:0001]
|
|
88
|
+
# IPv6-address-literal = "IPv6:" IPv6-addr
|
|
89
|
+
# IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
|
|
90
|
+
# IPv6-hex = 1*4HEXDIG
|
|
91
|
+
# IPv6-full = IPv6-hex 7(":" IPv6-hex)
|
|
92
|
+
# IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::"
|
|
93
|
+
# [IPv6-hex *5(":" IPv6-hex)]
|
|
94
|
+
# ; The "::" represents at least 2 16-bit groups of
|
|
95
|
+
# ; zeros. No more than 6 groups in addition to the
|
|
96
|
+
# ; "::" may be present.
|
|
97
|
+
# IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
|
|
98
|
+
# IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::"
|
|
99
|
+
# [IPv6-hex *3(":" IPv6-hex) ":"]
|
|
100
|
+
# IPv4-address-literal
|
|
101
|
+
# ; The "::" represents at least 2 16-bit groups of
|
|
102
|
+
# ; zeros. No more than 4 groups in addition to the
|
|
103
|
+
# ; "::" and IPv4-address-literal may be present.
|
|
104
|
+
return true if dpart.size > 2 && dpart.rindex(':') > 7
|
|
105
|
+
end
|
|
106
|
+
return false
|
|
66
107
|
end
|
|
67
108
|
|
|
68
109
|
# find() returns a valid internet hostname found from the argument
|
|
@@ -70,8 +111,7 @@ module Sisimai
|
|
|
70
111
|
# @return string A valid internet hostname found in the argument
|
|
71
112
|
# @since v5.2.0
|
|
72
113
|
def find(argv1 = "")
|
|
73
|
-
return ""
|
|
74
|
-
return "" unless argv1.size > 4
|
|
114
|
+
return "" if argv1.nil? || argv1.size < 5
|
|
75
115
|
|
|
76
116
|
sourcetext = argv1.downcase
|
|
77
117
|
sourcelist = []
|
|
@@ -91,7 +131,7 @@ module Sisimai
|
|
|
91
131
|
Sandwiched.each do |e|
|
|
92
132
|
# Check a hostname exists between the $e->[0] and $e->[1] at array "Sandwiched"
|
|
93
133
|
# Each array in Sandwiched have 2 elements
|
|
94
|
-
next
|
|
134
|
+
next if Sisimai::String.aligned(sourcetext, e) == false
|
|
95
135
|
|
|
96
136
|
p1 = sourcetext.index(e[0])
|
|
97
137
|
p2 = sourcetext.index(e[1])
|
|
@@ -112,7 +152,7 @@ module Sisimai
|
|
|
112
152
|
end
|
|
113
153
|
ExistUntil.each do |e|
|
|
114
154
|
# ExistUntil have some strings, not an array
|
|
115
|
-
p1 = sourcetext.index(e); next
|
|
155
|
+
p1 = sourcetext.index(e); next if p1.nil?
|
|
116
156
|
sourcelist = sourcetext[0, p1].split(" ")
|
|
117
157
|
throw :MAKELIST
|
|
118
158
|
end
|
|
@@ -126,9 +166,9 @@ module Sisimai
|
|
|
126
166
|
e.chop! if e[-1, 1] == "." # Remove "." at the end of the string
|
|
127
167
|
e.delete!('[]()<>:;')
|
|
128
168
|
|
|
129
|
-
next
|
|
130
|
-
next
|
|
131
|
-
next
|
|
169
|
+
next if e.size < 4
|
|
170
|
+
next if e.include?(".") == false
|
|
171
|
+
next if Sisimai::RFC1123.is_internethost(e) == false
|
|
132
172
|
foundtoken << e
|
|
133
173
|
end
|
|
134
174
|
return "" if foundtoken.size == 0
|
data/lib/sisimai/rfc1894.rb
CHANGED
|
@@ -59,7 +59,7 @@ module Sisimai
|
|
|
59
59
|
|
|
60
60
|
SubtypeSet = {"addr" => "RFC822", "cdoe" => "SMTP", "host" => "DNS"}.freeze
|
|
61
61
|
ActionList = ["failed", "delayed", "delivered", "relayed", "expanded"].freeze
|
|
62
|
-
Correction = {'deliverable' => 'delivered', 'expired' => '
|
|
62
|
+
Correction = {'deliverable' => 'delivered', 'expired' => 'failed', 'failure' => 'failed'}
|
|
63
63
|
FieldGroup = {
|
|
64
64
|
'original-recipient' => 'addr',
|
|
65
65
|
'final-recipient' => 'addr',
|
|
@@ -114,16 +114,16 @@ module Sisimai
|
|
|
114
114
|
|
|
115
115
|
FieldNames[0].each_key do |e|
|
|
116
116
|
# Per-Message fields
|
|
117
|
-
next
|
|
118
|
-
next
|
|
117
|
+
next if label != e
|
|
118
|
+
next if argv0.include?(FieldNames[0][label]) == false
|
|
119
119
|
match = 1; break
|
|
120
120
|
end
|
|
121
121
|
return match if match > 0
|
|
122
122
|
|
|
123
123
|
FieldNames[1].each_key do |e|
|
|
124
124
|
# Per-Recipient field
|
|
125
|
-
next
|
|
126
|
-
next
|
|
125
|
+
next if label != e
|
|
126
|
+
next if argv0.include?(FieldNames[1][label]) == false
|
|
127
127
|
match = 2; break
|
|
128
128
|
end
|
|
129
129
|
return match
|
|
@@ -147,9 +147,7 @@ module Sisimai
|
|
|
147
147
|
label = Sisimai::RFC1894.label(argv0)
|
|
148
148
|
group = FieldGroup[label] || ''
|
|
149
149
|
parts = argv0.split(":", 2); parts[1] = parts[1].nil? ? "" : Sisimai::String.sweep(parts[1])
|
|
150
|
-
|
|
151
|
-
return nil if group.empty?
|
|
152
|
-
return nil unless CapturesOn[group]
|
|
150
|
+
return nil if group.empty? || CapturesOn[group].nil?
|
|
153
151
|
|
|
154
152
|
# Try to match with each pattern of Per-Message field, Per-Recipient field
|
|
155
153
|
# - 0: Field-Name
|
data/lib/sisimai/rfc2045.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Sisimai
|
|
|
9
9
|
# @param [String] argvs String to be checked
|
|
10
10
|
# @return [Boolean] false: Not MIME encoded string, true: MIME encoded string
|
|
11
11
|
def is_encoded(argv1)
|
|
12
|
-
return false
|
|
12
|
+
return false if argv1.nil? || argv1.empty?
|
|
13
13
|
|
|
14
14
|
text1 = argv1.delete('"')
|
|
15
15
|
mime1 = false
|
|
@@ -69,7 +69,7 @@ module Sisimai
|
|
|
69
69
|
# utf8 => UTF-8
|
|
70
70
|
ctxcharset = 'UTF-8' if ctxcharset.casecmp('UTF8') == 0
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
if ctxcharset.casecmp('UTF-8') != 0
|
|
73
73
|
# Characterset is not UTF-8
|
|
74
74
|
begin
|
|
75
75
|
p = p.encode!('UTF-8', ctxcharset)
|
|
@@ -109,12 +109,11 @@ module Sisimai
|
|
|
109
109
|
def parameter(argv0 = '', argv1 = '')
|
|
110
110
|
return "" if argv0.empty?
|
|
111
111
|
parameterq = argv1.size > 0 ? argv1 + '=' : ''
|
|
112
|
-
paramindex = argv1.size > 0 ? argv0.index(parameterq) : 0
|
|
113
|
-
return '' unless paramindex
|
|
112
|
+
paramindex = argv1.size > 0 ? argv0.index(parameterq) : 0; return '' if paramindex.nil?
|
|
114
113
|
|
|
115
114
|
# Find the value of the parameter name specified in argv1
|
|
116
115
|
foundtoken = argv0[paramindex + parameterq.size, argv0.size].split(';', 2)[0] || ''
|
|
117
|
-
foundtoken = foundtoken.downcase
|
|
116
|
+
foundtoken = foundtoken.downcase if argv1 != 'boundary'
|
|
118
117
|
foundtoken = foundtoken.delete('"').delete("'")
|
|
119
118
|
return foundtoken
|
|
120
119
|
end
|
|
@@ -147,8 +146,8 @@ module Sisimai
|
|
|
147
146
|
return nil if block.empty?
|
|
148
147
|
|
|
149
148
|
(upperchunk, lowerchunk) = block.split("\n\n", 2)
|
|
150
|
-
return ['', ''] if
|
|
151
|
-
return ['', '']
|
|
149
|
+
return ['', ''] if upperchunk.nil? || upperchunk.empty?
|
|
150
|
+
return ['', ''] if upperchunk.index('Content-Type').nil?
|
|
152
151
|
|
|
153
152
|
headerpart = ['', ''] # ["text/plain; charset=iso-2022-jp; ...", "quoted-printable"]
|
|
154
153
|
multipart1 = [] # [headerpart, "body"]
|
|
@@ -224,8 +223,10 @@ module Sisimai
|
|
|
224
223
|
multiparts = argv1.split(Regexp.new(Regexp.escape(boundary01) + "\n"))
|
|
225
224
|
partstable = []
|
|
226
225
|
|
|
227
|
-
|
|
228
|
-
multiparts.
|
|
226
|
+
# Remove empty or useless preamble and epilogue of multipart/* block
|
|
227
|
+
multiparts.shift if multiparts[0].size < 8
|
|
228
|
+
return [] if multiparts.empty?
|
|
229
|
+
multiparts.pop if multiparts.size > 2 && multiparts[-1].size < 8
|
|
229
230
|
|
|
230
231
|
while e = multiparts.shift do
|
|
231
232
|
# Check each part and breaks up internal multipart/* block
|
|
@@ -234,8 +235,7 @@ module Sisimai
|
|
|
234
235
|
# There is nested multipart/* block
|
|
235
236
|
boundary02 = boundary(f[0], -1); next if boundary02.empty?
|
|
236
237
|
bodyinside = f[-1].split("\n\n", 2)[-1]
|
|
237
|
-
next
|
|
238
|
-
next unless bodyinside.index(boundary02)
|
|
238
|
+
next if bodyinside.size < 9 || bodyinside.index(boundary02).nil?
|
|
239
239
|
|
|
240
240
|
v = levelout(f[0], bodyinside)
|
|
241
241
|
partstable += v if v.size > 0
|
|
@@ -299,6 +299,16 @@ module Sisimai
|
|
|
299
299
|
if ctencoding == 'base64'
|
|
300
300
|
# Content-Transfer-Encoding: base64
|
|
301
301
|
bodystring = decodeB(bodyinside) || ''
|
|
302
|
+
dontappend = false; while first10 = bodystring[0,10] do
|
|
303
|
+
# Don't pick the decoded part as an error message when the part is
|
|
304
|
+
# - BASE64 encoded.
|
|
305
|
+
# - the value of the charset is not utf-8.
|
|
306
|
+
# - NOT a plain text.
|
|
307
|
+
break if Sisimai::String.aligned(e[0], ['charset', '=', 'utf-8'])
|
|
308
|
+
break unless first10 =~ /[\x00-\x08\x0E-\x1F\x7F-]/
|
|
309
|
+
dontappend = true; break
|
|
310
|
+
end
|
|
311
|
+
next if dontappend
|
|
302
312
|
|
|
303
313
|
elsif ctencoding == 'quoted-printable'
|
|
304
314
|
# Content-Transfer-Encoding: quoted-printable
|
|
@@ -328,7 +338,7 @@ module Sisimai
|
|
|
328
338
|
# the following errors:
|
|
329
339
|
# - incompatible character encodings: ASCII-8BIT and UTF-8
|
|
330
340
|
# - invalid byte sequence in UTF-8
|
|
331
|
-
|
|
341
|
+
if bodystring.encoding.to_s != 'UTF-8'
|
|
332
342
|
# ASCII-8BIT or other 8bit encodings
|
|
333
343
|
ctxcharset = parameter(e[0], 'charset')
|
|
334
344
|
if ctxcharset.empty?
|
|
@@ -346,6 +356,8 @@ module Sisimai
|
|
|
346
356
|
|
|
347
357
|
else
|
|
348
358
|
# There is no Content-Transfer-Encoding header in the part
|
|
359
|
+
be = bodyinside.encoding.to_s
|
|
360
|
+
bodyinside = Sisimai::String.to_utf8(bodyinside, be) if be != 'UTF-8'
|
|
349
361
|
bodystring += bodyinside
|
|
350
362
|
end
|
|
351
363
|
|
|
@@ -357,7 +369,7 @@ module Sisimai
|
|
|
357
369
|
end
|
|
358
370
|
|
|
359
371
|
# Append "\n" when the last character of $bodystring is not LF
|
|
360
|
-
bodystring += "\n\n"
|
|
372
|
+
bodystring += "\n\n" if bodystring[-2, 2] != "\n\n"
|
|
361
373
|
flattenout += bodystring
|
|
362
374
|
end
|
|
363
375
|
|
|
@@ -22,8 +22,7 @@ module Sisimai
|
|
|
22
22
|
# @param string argv1 A line of a bounce mail
|
|
23
23
|
# @return string An MTA name of the 3rd party
|
|
24
24
|
def returnedby(argv1 = "")
|
|
25
|
-
return ""
|
|
26
|
-
return "" unless argv1.start_with?("X-")
|
|
25
|
+
return "" if argv1.nil? || argv1.start_with?("X-") == false
|
|
27
26
|
|
|
28
27
|
ThirdParty.each_key do |e|
|
|
29
28
|
# Does the argument include the 3rd party specific field?
|
|
@@ -53,7 +52,7 @@ module Sisimai
|
|
|
53
52
|
MessagesOf = {
|
|
54
53
|
"bad-domain" => "hostunknown",
|
|
55
54
|
"bad-mailbox" => "userunknown",
|
|
56
|
-
"inactive-mailbox" => "
|
|
55
|
+
"inactive-mailbox" => "suspend",
|
|
57
56
|
"message-expired" => "expired",
|
|
58
57
|
"no-answer-from-host" => "networkerror",
|
|
59
58
|
"policy-related" => "policyviolation",
|
data/lib/sisimai/rfc3464.rb
CHANGED
|
@@ -151,7 +151,7 @@ module Sisimai
|
|
|
151
151
|
if o[0] == "final-recipient"
|
|
152
152
|
# Final-Recipient: rfc822; kijitora@example.jp
|
|
153
153
|
# Final-Recipient: x400; /PN=...
|
|
154
|
-
cv = Sisimai::Address.s3s4(o[2]); next
|
|
154
|
+
cv = Sisimai::Address.s3s4(o[2]); next if Sisimai::Address.is_emailaddress(cv) == false
|
|
155
155
|
cw = dscontents.size; next if cw > 0 && cv == dscontents[cw - 1]["recipient"]
|
|
156
156
|
|
|
157
157
|
if v["recipient"] != ""
|
|
@@ -177,18 +177,18 @@ module Sisimai
|
|
|
177
177
|
# Status: 4.0.0 (cat.example.net: host name lookup failure)
|
|
178
178
|
v["diagnosis"] += " #{o[4]} "
|
|
179
179
|
end
|
|
180
|
-
next
|
|
180
|
+
next if FieldTable[o[0]].nil?
|
|
181
181
|
next if o[3] == "host" && Sisimai::RFC1123.is_internethost(o[2]) == false
|
|
182
182
|
v[FieldTable[o[0]]] = o[2]
|
|
183
183
|
|
|
184
|
-
next
|
|
184
|
+
next if f != 1
|
|
185
185
|
permessage[FieldTable[o[0]]] = o[2]
|
|
186
186
|
end
|
|
187
187
|
else
|
|
188
188
|
# Check that the line is a continued line of the value of Diagnostic-Code: field or not
|
|
189
189
|
if e.start_with?("X-") && e.include?(": ")
|
|
190
190
|
# This line is a MTA-Specific fields begins with "X-"
|
|
191
|
-
next
|
|
191
|
+
next if Sisimai::RFC3464::ThirdParty.is3rdparty(e) == false
|
|
192
192
|
cv = Sisimai::RFC3464::ThirdParty.xfield(e)
|
|
193
193
|
|
|
194
194
|
if cv.size > 0 && FieldTable[cv[0].downcase] == nil
|
|
@@ -197,7 +197,7 @@ module Sisimai
|
|
|
197
197
|
v["reason"] = cv[4][p1 + 1, cv[4].size] if cv[4].start_with?("reason:")
|
|
198
198
|
else
|
|
199
199
|
# Set the value picked from "X-*" field to $dscontents when the current value is empty
|
|
200
|
-
z = FieldTable[cv[0].downcase]; next
|
|
200
|
+
z = FieldTable[cv[0].downcase]; next if z.nil?
|
|
201
201
|
v[z] ||= cv[2]
|
|
202
202
|
end
|
|
203
203
|
else
|
|
@@ -211,7 +211,7 @@ module Sisimai
|
|
|
211
211
|
|
|
212
212
|
# Diagnostic-Code: SMTP; 550-5.7.26 The MAIL FROM domain [email.example.jp]
|
|
213
213
|
# has an SPF record with a hard fail
|
|
214
|
-
next
|
|
214
|
+
next if e.start_with?(" ") == false
|
|
215
215
|
v["diagnosis"] += " #{Sisimai::String.sweep(e)}"
|
|
216
216
|
end
|
|
217
217
|
end
|