sisimai 5.5.0 → 5.6.0
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/ChangeLog.md +21 -0
- data/LICENSE +1 -1
- data/README-JA.md +15 -12
- data/README.md +16 -13
- data/lib/sisimai/fact.rb +17 -2
- data/lib/sisimai/lhost/amazonses.rb +1 -1
- data/lib/sisimai/lhost/einsundeins.rb +1 -1
- data/lib/sisimai/lhost/exchange2007.rb +2 -2
- data/lib/sisimai/lhost/exim.rb +6 -8
- data/lib/sisimai/lhost/qmail.rb +5 -5
- data/lib/sisimai/message.rb +2 -0
- data/lib/sisimai/reason/authfailure.rb +9 -13
- data/lib/sisimai/reason/badreputation.rb +7 -7
- data/lib/sisimai/reason/blocked.rb +57 -83
- data/lib/sisimai/reason/contenterror.rb +14 -8
- data/lib/sisimai/reason/{mesgtoobig.rb → emailtoolarge.rb} +22 -25
- data/lib/sisimai/reason/expired.rb +16 -23
- data/lib/sisimai/reason/filtered.rb +13 -17
- data/lib/sisimai/reason/hasmoved.rb +2 -1
- data/lib/sisimai/reason/hostunknown.rb +16 -19
- data/lib/sisimai/reason/mailboxfull.rb +27 -49
- data/lib/sisimai/reason/networkerror.rb +16 -16
- data/lib/sisimai/reason/norelaying.rb +19 -19
- data/lib/sisimai/reason/notaccept.rb +6 -8
- data/lib/sisimai/reason/notcompliantrfc.rb +5 -9
- data/lib/sisimai/reason/policyviolation.rb +11 -25
- data/lib/sisimai/reason/ratelimited.rb +62 -0
- data/lib/sisimai/reason/rejected.rb +45 -59
- data/lib/sisimai/reason/requireptr.rb +13 -25
- data/lib/sisimai/reason/securityerror.rb +13 -19
- data/lib/sisimai/reason/spamdetected.rb +51 -101
- data/lib/sisimai/reason/suspend.rb +26 -24
- data/lib/sisimai/reason/systemerror.rb +19 -23
- data/lib/sisimai/reason/systemfull.rb +1 -1
- data/lib/sisimai/reason/userunknown.rb +79 -112
- data/lib/sisimai/reason/virusdetected.rb +6 -8
- data/lib/sisimai/reason.rb +14 -14
- data/lib/sisimai/rhost/apple.rb +5 -5
- data/lib/sisimai/rhost/cloudflare.rb +2 -0
- data/lib/sisimai/rhost/cox.rb +22 -20
- data/lib/sisimai/rhost/facebook.rb +16 -16
- data/lib/sisimai/rhost/franceptt.rb +8 -3
- data/lib/sisimai/rhost/godaddy.rb +33 -15
- data/lib/sisimai/rhost/google.rb +63 -64
- data/lib/sisimai/rhost/iua.rb +1 -1
- data/lib/sisimai/rhost/messagelabs.rb +12 -12
- data/lib/sisimai/rhost/microsoft.rb +82 -86
- data/lib/sisimai/rhost/mimecast.rb +34 -34
- data/lib/sisimai/rhost/nttdocomo.rb +2 -2
- data/lib/sisimai/rhost/spectrum.rb +7 -7
- data/lib/sisimai/rhost/tencent.rb +9 -11
- data/lib/sisimai/rhost/yahooinc.rb +7 -8
- data/lib/sisimai/smtp/command.rb +2 -0
- data/lib/sisimai/smtp/status.rb +50 -90
- data/lib/sisimai/string.rb +0 -15
- data/lib/sisimai/version.rb +1 -1
- metadata +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +0 -47
- data/lib/sisimai/reason/speeding.rb +0 -47
- data/lib/sisimai/reason/toomanyconn.rb +0 -59
|
@@ -2,27 +2,25 @@ module Sisimai
|
|
|
2
2
|
module Reason
|
|
3
3
|
# This is the error that a sent email size is too big for a destination mail server. In many
|
|
4
4
|
# case, There are many attachment files with email, or the file size is too large. Sisimai will
|
|
5
|
-
# set "
|
|
6
|
-
# is "5.3.4".
|
|
7
|
-
module
|
|
5
|
+
# set "emailtoolarge" to the reason of email bounce if the value of Status: field in a bounce
|
|
6
|
+
# email is "5.2.3" or "5.3.4".
|
|
7
|
+
module EmailTooLarge
|
|
8
8
|
class << self
|
|
9
9
|
Index = [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'size limit',
|
|
22
|
-
'taille limite du message atteinte',
|
|
10
|
+
"line limit exceeded",
|
|
11
|
+
"mail file size exceeds the maximum size allowed for mail delivery",
|
|
12
|
+
"message too large",
|
|
13
|
+
"size limit",
|
|
14
|
+
"taille limite du message atteinte",
|
|
15
|
+
].freeze
|
|
16
|
+
Pairs = [
|
|
17
|
+
["exceeded", "message size"],
|
|
18
|
+
["message ", "exceeds ", "limit"],
|
|
19
|
+
["message ", "size", "exceed"],
|
|
20
|
+
["message ", "too", "big"],
|
|
23
21
|
].freeze
|
|
24
22
|
|
|
25
|
-
def text; return '
|
|
23
|
+
def text; return 'emailtoolarge'; end
|
|
26
24
|
def description; return 'Email rejected due to an email size is too big for a destination mail server'; end
|
|
27
25
|
|
|
28
26
|
# Try to match that the given text and regular expressions
|
|
@@ -31,6 +29,7 @@ module Sisimai
|
|
|
31
29
|
def match(argv1)
|
|
32
30
|
return false if argv1.nil? || argv1.empty?
|
|
33
31
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
32
|
+
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
34
33
|
return false
|
|
35
34
|
end
|
|
36
35
|
|
|
@@ -40,18 +39,18 @@ module Sisimai
|
|
|
40
39
|
# false: is not big
|
|
41
40
|
# @see http://www.ietf.org/rfc/rfc2822.txt
|
|
42
41
|
def true(argvs)
|
|
43
|
-
return true if argvs['reason'] == '
|
|
42
|
+
return true if argvs['reason'] == 'emailtoolarge'
|
|
44
43
|
|
|
45
44
|
statuscode = argvs['deliverystatus'] || ''
|
|
46
45
|
tempreason = Sisimai::SMTP::Status.name(statuscode)
|
|
47
46
|
|
|
48
|
-
# Delivery status code points "
|
|
47
|
+
# Delivery status code points "emailtoolarge".
|
|
49
48
|
# Status: 5.3.4
|
|
50
49
|
# Diagnostic-Code: SMTP; 552 5.3.4 Error: message file too big
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
#
|
|
54
|
-
return
|
|
50
|
+
#
|
|
51
|
+
# Status: 5.2.3
|
|
52
|
+
# Deiagnostic-Code: Message length exceeds administrative limit
|
|
53
|
+
return true if tempreason == 'emailtoolarge'
|
|
55
54
|
return match(argvs['diagnosticcode'].downcase)
|
|
56
55
|
end
|
|
57
56
|
|
|
@@ -60,5 +59,3 @@ module Sisimai
|
|
|
60
59
|
end
|
|
61
60
|
end
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
@@ -7,32 +7,25 @@ module Sisimai
|
|
|
7
7
|
# the message you sent has been in the queue for long time.
|
|
8
8
|
module Expired
|
|
9
9
|
class << self
|
|
10
|
-
require 'sisimai/string'
|
|
11
|
-
|
|
12
10
|
Index = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'message timed out',
|
|
27
|
-
'retry time not reached for any host after a long failure period',
|
|
28
|
-
'server did not respond',
|
|
29
|
-
'this message has been in the queue too long',
|
|
30
|
-
'unable to deliver message after multiple retries',
|
|
31
|
-
'was not reachable within the allowed queue period',
|
|
32
|
-
'your message could not be delivered for more than',
|
|
11
|
+
"connection timed out",
|
|
12
|
+
"could not find a gateway for",
|
|
13
|
+
"delivery attempts will continue to be",
|
|
14
|
+
"failed to deliver to domain ",
|
|
15
|
+
"have been failing for a long time",
|
|
16
|
+
"has been delayed",
|
|
17
|
+
"it has not been collected after",
|
|
18
|
+
"message could not be delivered for more than",
|
|
19
|
+
"message expired, ",
|
|
20
|
+
"message has been in the queue too long",
|
|
21
|
+
"message timed out",
|
|
22
|
+
"server did not respond",
|
|
23
|
+
"unable to deliver message after multiple retries",
|
|
33
24
|
].freeze
|
|
34
25
|
Pairs = [
|
|
35
|
-
[
|
|
26
|
+
["could not be delivered for", " days"],
|
|
27
|
+
["delivery ", "expired"],
|
|
28
|
+
["not", "reach", "period"],
|
|
36
29
|
].freeze
|
|
37
30
|
|
|
38
31
|
def text; return 'expired'; end
|
|
@@ -10,22 +10,18 @@ module Sisimai
|
|
|
10
10
|
module Filtered
|
|
11
11
|
class << self
|
|
12
12
|
Index = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'has restricted sms e-mail', # AT&T
|
|
17
|
-
'is not accepting any mail',
|
|
13
|
+
"account is protected by",
|
|
14
|
+
"has restricted sms e-mail", # AT&T
|
|
15
|
+
"is not accepting any mail",
|
|
18
16
|
"message filtered",
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
'we failed to deliver mail because the following address recipient id refuse to receive mail', # Willcom
|
|
28
|
-
'you have been blocked by the recipient',
|
|
17
|
+
"message rejected due to user rules",
|
|
18
|
+
"not found recipient account",
|
|
19
|
+
"recipient id refuse to receive mail", # Willcom
|
|
20
|
+
"recipient is only accepting mail from specific email addresses", # AOL Phoenix
|
|
21
|
+
"refused due to recipient preferences", # Facebook
|
|
22
|
+
"user refuses to receive this mail",
|
|
23
|
+
"user reject",
|
|
24
|
+
"you have been blocked by the recipient",
|
|
29
25
|
].freeze
|
|
30
26
|
|
|
31
27
|
def text; return 'filtered'; end
|
|
@@ -48,7 +44,6 @@ module Sisimai
|
|
|
48
44
|
def true(argvs)
|
|
49
45
|
return true if argvs['reason'] == 'filtered'
|
|
50
46
|
|
|
51
|
-
require 'sisimai/reason/userunknown'
|
|
52
47
|
tempreason = Sisimai::SMTP::Status.name(argvs['deliverystatus'])
|
|
53
48
|
return false if tempreason == 'suspend'
|
|
54
49
|
|
|
@@ -56,12 +51,13 @@ module Sisimai
|
|
|
56
51
|
thecommand = argvs['command'] || ''
|
|
57
52
|
if tempreason == 'filtered'
|
|
58
53
|
# Delivery status code points "filtered".
|
|
54
|
+
require 'sisimai/reason/userunknown'
|
|
59
55
|
return true if Sisimai::Reason::UserUnknown.match(issuedcode) || match(issuedcode)
|
|
60
56
|
else
|
|
61
57
|
# The value of "reason" isn't "filtered" when the value of "command" is an SMTP command
|
|
62
58
|
# to be sent before the SMTP DATA command because all the MTAs read the headers and the
|
|
63
59
|
# entire message body after the DATA command.
|
|
64
|
-
return false if
|
|
60
|
+
return false if Sisimai::SMTP::Command::ExceptDATA.include?(thecommand)
|
|
65
61
|
return true if match(issuedcode) || Sisimai::Reason::UserUnknown.match(issuedcode)
|
|
66
62
|
end
|
|
67
63
|
return false
|
|
@@ -28,7 +28,8 @@ module Sisimai
|
|
|
28
28
|
# false: Has not moved
|
|
29
29
|
# @see http://www.ietf.org/rfc/rfc2822.txt
|
|
30
30
|
def true(argvs)
|
|
31
|
-
return true
|
|
31
|
+
return true if argvs['reason'] == 'hasmoved'
|
|
32
|
+
return false if Sisimai::SMTP::Command::BeforeRCPT.include?(argvs['command'])
|
|
32
33
|
return match(argvs['diagnosticcode'].downcase)
|
|
33
34
|
end
|
|
34
35
|
|
|
@@ -6,26 +6,22 @@ module Sisimai
|
|
|
6
6
|
# Status: field in a bounce mail is "5.1.2".
|
|
7
7
|
module HostUnknown
|
|
8
8
|
class << self
|
|
9
|
-
require 'sisimai/string'
|
|
10
|
-
|
|
11
9
|
Index = [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'unrouteable address',
|
|
10
|
+
"domain is not reachable",
|
|
11
|
+
"domain mentioned in email address is unknown",
|
|
12
|
+
"domain must exist",
|
|
13
|
+
"host or domain name not found",
|
|
14
|
+
"host unknown",
|
|
15
|
+
"host unreachable",
|
|
16
|
+
"name or service not known",
|
|
17
|
+
"no such domain",
|
|
18
|
+
"recipient address rejected: unknown domain name",
|
|
19
|
+
"unknown host",
|
|
20
|
+
].freeze
|
|
21
|
+
Pairs = [
|
|
22
|
+
["domain ", "not exist"],
|
|
23
|
+
["unrout", "able ", "address"],
|
|
27
24
|
].freeze
|
|
28
|
-
Pairs = [['553 ', ' does not exist']].freeze
|
|
29
25
|
|
|
30
26
|
def text; return 'hostunknown'; end
|
|
31
27
|
def description; return "Delivery failed due to a domain part of a recipient's email address does not exist"; end
|
|
@@ -47,7 +43,8 @@ module Sisimai
|
|
|
47
43
|
# false: is not unknown host.
|
|
48
44
|
# @see http://www.ietf.org/rfc/rfc2822.txt
|
|
49
45
|
def true(argvs)
|
|
50
|
-
return true
|
|
46
|
+
return true if argvs['reason'] == 'hostunknown'
|
|
47
|
+
return false if Sisimai::SMTP::Command::BeforeRCPT.include?(argvs['command'])
|
|
51
48
|
|
|
52
49
|
issuedcode = argvs['diagnosticcode'].downcase || ''
|
|
53
50
|
statuscode = argvs['deliverystatus'] || ''
|
|
@@ -8,55 +8,32 @@ module Sisimai
|
|
|
8
8
|
module MailboxFull
|
|
9
9
|
class << self
|
|
10
10
|
Index = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
'maildir delivery failed: domaindisk quota ',
|
|
38
|
-
'mailfolder is full',
|
|
39
|
-
'no space left on device',
|
|
40
|
-
'not enough disk space',
|
|
41
|
-
'not enough storage space in',
|
|
42
|
-
'not sufficient disk space',
|
|
43
|
-
'over the allowed quota',
|
|
44
|
-
'quota exceeded',
|
|
45
|
-
'quota violation for',
|
|
46
|
-
'recipient reached disk quota',
|
|
47
|
-
'recipient rejected: mailbox would exceed maximum allowed storage',
|
|
48
|
-
'the recipient mailbox has exceeded its disk space limit',
|
|
49
|
-
"the user's space has been used up",
|
|
50
|
-
'the user you are trying to reach is over quota',
|
|
51
|
-
'too much mail data', # @docomo.ne.jp
|
|
52
|
-
'user has exceeded quota, bouncing mail',
|
|
53
|
-
'user has too many messages on the server',
|
|
54
|
-
'user is over quota',
|
|
55
|
-
'user is over the quota',
|
|
56
|
-
'user over quota',
|
|
57
|
-
'user over quota. (#5.1.1)', # qmail-toaster
|
|
58
|
-
'was automatically rejected: quota exceeded',
|
|
59
|
-
'would be over the allowed quota',
|
|
11
|
+
"452 insufficient disk space",
|
|
12
|
+
"account disabled temporarly for exceeding receiving limits",
|
|
13
|
+
"boite du destinataire pleine",
|
|
14
|
+
"exceeded storage allocation",
|
|
15
|
+
"full mailbox",
|
|
16
|
+
"mailbox size limit exceeded",
|
|
17
|
+
"mailbox would exceed maximum allowed storage",
|
|
18
|
+
"mailfolder is full",
|
|
19
|
+
"no space left on device",
|
|
20
|
+
"not sufficient disk space",
|
|
21
|
+
"quota violation for",
|
|
22
|
+
"too much mail data", # @docomo.ne.jp
|
|
23
|
+
"user has exceeded quota, bouncing mail",
|
|
24
|
+
"user has too many messages on the server",
|
|
25
|
+
"user's space has been used up",
|
|
26
|
+
].freeze
|
|
27
|
+
Pairs = [
|
|
28
|
+
["account is ", " quota"],
|
|
29
|
+
["disk", "quota"],
|
|
30
|
+
["enough ", " space"],
|
|
31
|
+
["mailbox ", "exceeded", " limit"],
|
|
32
|
+
["mailbox ", "full"],
|
|
33
|
+
["mailbox ", "quota"],
|
|
34
|
+
["maildir ", "quota"],
|
|
35
|
+
["over ", "quota"],
|
|
36
|
+
["quota ", "exceeded"],
|
|
60
37
|
].freeze
|
|
61
38
|
|
|
62
39
|
def text; return 'mailboxfull'; end
|
|
@@ -68,6 +45,7 @@ module Sisimai
|
|
|
68
45
|
def match(argv1)
|
|
69
46
|
return false if argv1.nil? || argv1.empty?
|
|
70
47
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
48
|
+
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
71
49
|
return false
|
|
72
50
|
end
|
|
73
51
|
|
|
@@ -11,22 +11,21 @@ module Sisimai
|
|
|
11
11
|
module NetworkError
|
|
12
12
|
class << self
|
|
13
13
|
Index = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
'unrouteable mail domain',
|
|
14
|
+
"could not connect and send the mail to",
|
|
15
|
+
"dns records for the destination computer could not be found",
|
|
16
|
+
"host is unreachable",
|
|
17
|
+
"host name lookup failure",
|
|
18
|
+
"host not found, try again",
|
|
19
|
+
"maximum forwarding loop count exceeded",
|
|
20
|
+
"no route to host",
|
|
21
|
+
"too many hops",
|
|
22
|
+
"unable to resolve route ",
|
|
23
|
+
"unrouteable mail domain",
|
|
24
|
+
].freeze
|
|
25
|
+
Pairs = [
|
|
26
|
+
["malformed", "name server reply"],
|
|
27
|
+
["mail ", "loop"],
|
|
28
|
+
["message ", "loop"],
|
|
30
29
|
].freeze
|
|
31
30
|
|
|
32
31
|
def text; return 'networkerror'; end
|
|
@@ -38,6 +37,7 @@ module Sisimai
|
|
|
38
37
|
def match(argv1)
|
|
39
38
|
return false if argv1.nil? || argv1.empty?
|
|
40
39
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
40
|
+
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
41
41
|
return false
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -10,27 +10,26 @@ module Sisimai
|
|
|
10
10
|
module NoRelaying
|
|
11
11
|
class << self
|
|
12
12
|
Index = [
|
|
13
|
-
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
'relaying mail to ',
|
|
28
|
-
'specified domain is not allowed',
|
|
29
|
-
"that domain isn't in my list of allowed rcpthost",
|
|
30
|
-
'this system is not configured to relay mail',
|
|
31
|
-
'unable to relay ',
|
|
13
|
+
"as a relay",
|
|
14
|
+
"domain isn't in my list of allowed rcpthost",
|
|
15
|
+
"email address is not verified.",
|
|
16
|
+
"insecure mail relay",
|
|
17
|
+
"no relaying",
|
|
18
|
+
"not a gateway",
|
|
19
|
+
"not an open relay, so get lost",
|
|
20
|
+
"not local host",
|
|
21
|
+
"relay not permitted",
|
|
22
|
+
"relaying denied", # Sendmail
|
|
23
|
+
"relaying mail to ",
|
|
24
|
+
"send to a non-local e-mail address", # MailEnable
|
|
25
|
+
"specified domain is not allowed",
|
|
26
|
+
"unable to relay ",
|
|
32
27
|
"we don't handle mail for",
|
|
33
28
|
].freeze
|
|
29
|
+
Pairs = [
|
|
30
|
+
["relay ", "denied"],
|
|
31
|
+
[" not ", " to relay"],
|
|
32
|
+
].freeze
|
|
34
33
|
|
|
35
34
|
def text; return 'norelaying'; end
|
|
36
35
|
def description; return 'Email rejected with error message "Relaying Denied"'; end
|
|
@@ -41,6 +40,7 @@ module Sisimai
|
|
|
41
40
|
def match(argv1)
|
|
42
41
|
return false if argv1.nil? || argv1.empty?
|
|
43
42
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
43
|
+
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
44
44
|
return false
|
|
45
45
|
end
|
|
46
46
|
|
|
@@ -11,13 +11,11 @@ module Sisimai
|
|
|
11
11
|
class << self
|
|
12
12
|
# Destination mail server does not accept any message
|
|
13
13
|
Index = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'no route for current request',
|
|
20
|
-
'smtp protocol returned a permanent error',
|
|
14
|
+
"does not accept mail", # Sendmail, iCloud
|
|
15
|
+
"mail receiving disabled",
|
|
16
|
+
"name server: .: host not found", # Sendmail
|
|
17
|
+
"no mx record found for domain=", # Oath(Yahoo!)
|
|
18
|
+
"no route for current request",
|
|
21
19
|
].freeze
|
|
22
20
|
|
|
23
21
|
def text; return 'notaccept'; end
|
|
@@ -40,7 +38,7 @@ module Sisimai
|
|
|
40
38
|
def true(argvs)
|
|
41
39
|
return true if argvs['reason'] == 'notaccept'
|
|
42
40
|
return true if [521, 556].index(argvs['replycode'].to_i) # SMTP Reply Code is 554 or 556
|
|
43
|
-
return false if argvs['command']
|
|
41
|
+
return false if Sisimai::SMTP::Command::BeforeRCPT.include?(argvs['command'])
|
|
44
42
|
return match(argvs['diagnosticcode'].downcase)
|
|
45
43
|
end
|
|
46
44
|
|
|
@@ -7,16 +7,13 @@ module Sisimai
|
|
|
7
7
|
# example, there are multiple "Subject" headers in the email.
|
|
8
8
|
module NotCompliantRFC
|
|
9
9
|
class << self
|
|
10
|
-
require 'sisimai/string'
|
|
11
10
|
Index = [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
"duplicate header",
|
|
12
|
+
"message is not rfc 5322 compliant",
|
|
13
|
+
"multiple addresses in from: header are not accepted",
|
|
14
|
+
"rfc 1035 violation",
|
|
15
|
+
"https://support.google.com/mail/?p=rfcmessagenoncompliant",
|
|
15
16
|
].freeze
|
|
16
|
-
Pairs = [
|
|
17
|
-
[' multiple ', ' header'],
|
|
18
|
-
].freeze
|
|
19
|
-
|
|
20
17
|
|
|
21
18
|
def text; return 'notcompliantrfc'; end
|
|
22
19
|
def description; return 'Email rejected due to non-compliance with RFC'; end
|
|
@@ -27,7 +24,6 @@ module Sisimai
|
|
|
27
24
|
def match(argv1)
|
|
28
25
|
return false if argv1.nil? || argv1.empty?
|
|
29
26
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
30
|
-
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
31
27
|
return false
|
|
32
28
|
end
|
|
33
29
|
|
|
@@ -14,34 +14,21 @@ module Sisimai
|
|
|
14
14
|
#
|
|
15
15
|
module PolicyViolation
|
|
16
16
|
class << self
|
|
17
|
-
require 'sisimai/string'
|
|
18
|
-
|
|
19
17
|
Index = [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
'email not accepted for policy reasons',
|
|
18
|
+
"because the recipient is not accepting mail with ", # AOL Phoenix
|
|
19
|
+
"closed mailing list",
|
|
20
|
+
"delivery not authorized, message refused",
|
|
21
|
+
"denied by policy",
|
|
25
22
|
# http://kb.mimecast.com/Mimecast_Knowledge_Base/Administration_Console/Monitoring/Mimecast_SMTP_Error_Codes#554
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'message rejected due to local policy',
|
|
34
|
-
'messages with multiple addresses',
|
|
35
|
-
'rejected for policy reasons',
|
|
36
|
-
'protocol violation',
|
|
37
|
-
'the message was rejected by organization policy',
|
|
38
|
-
'this message was blocked because its content presents a potential', # https://support.google.com/mail/answer/6590
|
|
39
|
-
'we do not accept messages containing images or other attachments',
|
|
23
|
+
"email rejected due to security policies",
|
|
24
|
+
"for policy reasons",
|
|
25
|
+
"local policy violation",
|
|
26
|
+
"message bounced due to organizational settings",
|
|
27
|
+
"message given low priority",
|
|
28
|
+
"message was rejected by organization policy",
|
|
29
|
+
"protocol violation",
|
|
40
30
|
"you're using a mass mailer",
|
|
41
31
|
].freeze
|
|
42
|
-
Pairs = [
|
|
43
|
-
['you have exceeded the', 'allowable number of posts without solving a captcha'],
|
|
44
|
-
].freeze
|
|
45
32
|
|
|
46
33
|
def text; return 'policyviolation'; end
|
|
47
34
|
def description; return 'Email rejected due to policy violation on a destination host'; end
|
|
@@ -53,7 +40,6 @@ module Sisimai
|
|
|
53
40
|
def match(argv1)
|
|
54
41
|
return false if argv1.nil? || argv1.empty?
|
|
55
42
|
return true if Index.any? { |a| argv1.include?(a) }
|
|
56
|
-
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
57
43
|
return false
|
|
58
44
|
end
|
|
59
45
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Sisimai
|
|
2
|
+
module Reason
|
|
3
|
+
# Sisimai::Reason::RateLimited checks the bounce reason is "ratelimited" or not. This class is
|
|
4
|
+
# called only Sisimai::Reason class.
|
|
5
|
+
#
|
|
6
|
+
# This is the error that SMTP connection was rejected temporarily due to too many recipients or
|
|
7
|
+
# too many concurrency connections to the remote server. This reason has added in Sisimai 4.1.26.
|
|
8
|
+
#
|
|
9
|
+
# <kijitora@example.ne.jp>: host mx02.example.ne.jp[192.0.1.20] said:
|
|
10
|
+
# 452 4.3.2 Connection rate limit exceeded. (in reply to MAIL FROM command)
|
|
11
|
+
module RateLimited
|
|
12
|
+
class << self
|
|
13
|
+
Index = [
|
|
14
|
+
"has exceeded the max emails per hour ",
|
|
15
|
+
"please try again slower",
|
|
16
|
+
"receiving mail at a rate that prevents additional messages from being delivered",
|
|
17
|
+
"temporarily deferred due to unexpected volume or user complaints",
|
|
18
|
+
"throttling failure: ",
|
|
19
|
+
"too many errors from your ip", # Free.fr
|
|
20
|
+
"too many recipients", # ntt docomo
|
|
21
|
+
"too many smtp sessions for this host", # Sendmail(daemon.c)
|
|
22
|
+
"trop de connexions, ",
|
|
23
|
+
"we have already made numerous attempts to deliver this message",
|
|
24
|
+
].freeze
|
|
25
|
+
Pairs = [
|
|
26
|
+
["exceeded ", "allowable number of posts without solving a captcha"],
|
|
27
|
+
["connection ", "limit"],
|
|
28
|
+
["temporarily", "rate limited"],
|
|
29
|
+
["too many con", "s"],
|
|
30
|
+
].freeze
|
|
31
|
+
|
|
32
|
+
def text; return 'ratelimited'; end
|
|
33
|
+
def description; return 'SMTP connection rejected temporarily due to too many concurrency connections to the remote host'; end
|
|
34
|
+
|
|
35
|
+
# Try to match that the given text and regular expressions
|
|
36
|
+
# @param [String] argv1 String to be matched with regular expressions
|
|
37
|
+
# @return [Boolean] false: Did not match, true: Matched
|
|
38
|
+
def match(argv1)
|
|
39
|
+
return false if argv1.nil? || argv1.empty?
|
|
40
|
+
return true if Index.any? { |a| argv1.include?(a) }
|
|
41
|
+
return true if Pairs.any? { |a| Sisimai::String.aligned(argv1, a) }
|
|
42
|
+
return false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Rejected by domain or address filter ?
|
|
46
|
+
# @param [Sisimai::Fact] argvs Object to be detected the reason
|
|
47
|
+
# @return [Boolean] true: is rate limited
|
|
48
|
+
# false: is not rate limited
|
|
49
|
+
# @see http://www.ietf.org/rfc/rfc2822.txt
|
|
50
|
+
def true(argvs)
|
|
51
|
+
return true if argvs['reason'] == 'ratelimited'
|
|
52
|
+
return true if Sisimai::SMTP::Status.name(argvs['deliverystatus']) == 'ratelimited'
|
|
53
|
+
return match(argvs['diagnosticcode'].downcase)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|