sisimai 4.25.17-java → 5.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +406 -407
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +12 -12
- data/README-JA.md +142 -94
- data/README.md +282 -150
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +20 -16
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -325
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -45
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +13 -18
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +42 -23
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
data/lib/sisimai/rfc3834.rb
CHANGED
@@ -1,67 +1,65 @@
|
|
1
1
|
module Sisimai
|
2
2
|
# Sisimai::RFC3834 - RFC3834 auto reply message detector
|
3
3
|
module RFC3834
|
4
|
-
# Imported from p5-Sisimail/lib/Sisimai/RFC3834.pm
|
5
4
|
class << self
|
6
5
|
# http://tools.ietf.org/html/rfc3834
|
7
|
-
MarkingsOf = { :boundary =>
|
8
|
-
|
9
|
-
|
10
|
-
'
|
11
|
-
'
|
12
|
-
'
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|automatic[ ]reply:
|
17
|
-
|out[ ]of[ ](?:the[ ])*office:
|
18
|
-
)
|
19
|
-
/x,
|
6
|
+
MarkingsOf = { :boundary => '__SISIMAI_PSEUDO_BOUNDARY__' }
|
7
|
+
LowerLabel = %w[from to subject auto-submitted precedence x-apple-action].freeze
|
8
|
+
DoNotParse = {
|
9
|
+
'from' => ['root@', 'postmaster@', 'mailer-daemon@'],
|
10
|
+
'to' => ['root@'],
|
11
|
+
'subject' => [
|
12
|
+
'security information for', # sudo(1)
|
13
|
+
'mail failure -', # Exim
|
14
|
+
],
|
20
15
|
}.freeze
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
'from' => %r/(?:root|postmaster|mailer-daemon)[@]/,
|
28
|
-
'to' => %r/root[@]/,
|
16
|
+
AutoReply0 = {
|
17
|
+
# http://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml
|
18
|
+
'auto-submitted' => ['auto-generated', 'auto-replied', 'auto-notified'],
|
19
|
+
'precedence' => ['auto_reply'],
|
20
|
+
'subject' => ['auto:', 'auto response:', 'automatic reply:', 'out of office:', 'out of the office:'],
|
21
|
+
'x-apple-action' => ['vacation'],
|
29
22
|
}.freeze
|
30
23
|
SubjectSet = %r{\A(?>
|
31
|
-
(?:.+?)?
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
(?:.+?)?re:
|
25
|
+
|auto(?:[ ]response):
|
26
|
+
|automatic[ ]reply:
|
27
|
+
|out[ ]of[ ]office:
|
35
28
|
)
|
36
29
|
[ ]*(.+)\z
|
37
|
-
}
|
30
|
+
}x.freeze
|
38
31
|
|
39
32
|
# Detect auto reply message as RFC3834
|
40
33
|
# @param [Hash] mhead Message headers of a bounce email
|
41
34
|
# @param [String] mbody Message body of a bounce email
|
42
35
|
# @return [Hash] Bounce data list and message/rfc822 part
|
43
36
|
# @return [Nil] it failed to parse or the arguments are missing
|
44
|
-
def
|
37
|
+
def inquire(mhead, mbody)
|
45
38
|
leave = 0
|
46
39
|
match = 0
|
40
|
+
lower = {}
|
41
|
+
|
42
|
+
LowerLabel.each do |e|
|
43
|
+
# Set lower-cased value of each header related to auto-response
|
44
|
+
next unless mhead.has_key?(e)
|
45
|
+
lower[e] = mhead[e].downcase
|
46
|
+
end
|
47
47
|
|
48
48
|
# DETECT_EXCLUSION_MESSAGE
|
49
|
-
|
49
|
+
DoNotParse.each_key do |e|
|
50
50
|
# Exclude message from root@
|
51
|
-
next unless
|
52
|
-
next unless
|
53
|
-
next unless mhead[e].downcase =~ Excludings[e]
|
51
|
+
next unless lower[e]
|
52
|
+
next unless DoNotParse[e].any? { |a| lower[e].include?(a) }
|
54
53
|
leave = 1
|
55
54
|
break
|
56
55
|
end
|
57
56
|
return nil if leave > 0
|
58
57
|
|
59
|
-
#
|
60
|
-
|
58
|
+
# DETECT_AUTO_REPLY_MESSAGE0
|
59
|
+
AutoReply0.each_key do |e|
|
61
60
|
# RFC3834 Auto-Submitted and other headers
|
62
|
-
next unless
|
63
|
-
next unless
|
64
|
-
next unless mhead[e].downcase =~ AutoReply1[e]
|
61
|
+
next unless lower[e]
|
62
|
+
next unless AutoReply0[e].any? { |a| lower[e].include?(a) }
|
65
63
|
match += 1
|
66
64
|
break
|
67
65
|
end
|
@@ -95,16 +93,15 @@ module Sisimai
|
|
95
93
|
return nil unless recipients > 0
|
96
94
|
|
97
95
|
if mhead['content-type']
|
98
|
-
# Get the boundary string and set regular expression for matching with
|
99
|
-
|
100
|
-
|
101
|
-
MarkingsOf[:boundary] = %r/\A\Q#{b0}\E\z/ unless b0.empty?
|
96
|
+
# Get the boundary string and set regular expression for matching with the boundary string.
|
97
|
+
q = Sisimai::RFC2045.boundary(mhead['content-type'], 0) || ''
|
98
|
+
MarkingsOf[:boundary] = q unless q.empty?
|
102
99
|
end
|
103
100
|
|
104
101
|
# BODY_PARSER: Get vacation message
|
105
102
|
while e = bodyslices.shift do
|
106
103
|
# Read the first 5 lines except a blank line
|
107
|
-
countuntil += 1 if e
|
104
|
+
countuntil += 1 if e.include?(MarkingsOf[:boundary])
|
108
105
|
|
109
106
|
if e.empty?
|
110
107
|
# Check a blank line
|
@@ -113,8 +110,8 @@ module Sisimai
|
|
113
110
|
next
|
114
111
|
end
|
115
112
|
next unless e.include?(' ')
|
116
|
-
next if
|
117
|
-
next if
|
113
|
+
next if e.start_with?('Content-Type')
|
114
|
+
next if e.start_with?('Content-Transfer')
|
118
115
|
|
119
116
|
v['diagnosis'] ||= ''
|
120
117
|
v['diagnosis'] << e + ' '
|
@@ -127,7 +124,7 @@ module Sisimai
|
|
127
124
|
v['date'] = mhead['date']
|
128
125
|
v['status'] = ''
|
129
126
|
|
130
|
-
if cv =
|
127
|
+
if cv = lower['subject'].match(SubjectSet)
|
131
128
|
# Get the Subject header from the original message
|
132
129
|
rfc822part = 'Subject: ' << cv[1] + "\n"
|
133
130
|
end
|
data/lib/sisimai/rfc5322.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Sisimai
|
2
2
|
# Sisimai::RFC5322 provide methods for checking email address.
|
3
3
|
module RFC5322
|
4
|
-
# Imported from p5-Sisimail/lib/Sisimai/RFC5322.pm
|
5
4
|
class << self
|
5
|
+
require 'sisimai/string'
|
6
6
|
HeaderTable = {
|
7
7
|
:messageid => %w[message-id],
|
8
8
|
:subject => %w[subject],
|
@@ -12,46 +12,26 @@ module Sisimai
|
|
12
12
|
:recipient => %w[to delivered-to forward-path envelope-to x-envelope-to resent-to apparently-to],
|
13
13
|
}.freeze
|
14
14
|
|
15
|
-
build_regular_expressions = lambda do
|
16
|
-
# See http://www.ietf.org/rfc/rfc5322.txt
|
17
|
-
# or http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html ...
|
18
|
-
# addr-spec = local-part "@" domain
|
19
|
-
# local-part = dot-atom / quoted-string / obs-local-part
|
20
|
-
# domain = dot-atom / domain-literal / obs-domain
|
21
|
-
# domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
|
22
|
-
# dcontent = dtext / quoted-pair
|
23
|
-
# dtext = NO-WS-CTL / ; Non white space controls
|
24
|
-
# %d33-90 / ; The rest of the US-ASCII
|
25
|
-
# %d94-126 ; characters not including "[",
|
26
|
-
# ; "]", or "\"
|
27
|
-
re = { rfc5322: nil, ignored: nil, domain: nil }
|
28
|
-
atom = %r([a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)o
|
29
|
-
quoted_string = %r/"(?:\\[^\r\n]|[^\\"])*"/o
|
30
|
-
domain_literal = %r/\[(?:\\[\x01-\x09\x0B-\x0c\x0e-\x7f]|[\x21-\x5a\x5e-\x7e])*\]/o
|
31
|
-
dot_atom = %r/#{atom}(?:[.]#{atom})*/o
|
32
|
-
local_part = %r/(?:#{dot_atom}|#{quoted_string})/o
|
33
|
-
domain = %r/(?:#{dot_atom}|#{domain_literal})/o
|
34
|
-
|
35
|
-
re[:rfc5322] = %r/\A#{local_part}[@]#{domain}\z/o
|
36
|
-
re[:ignored] = %r/\A#{local_part}[.]*[@]#{domain}\z/o
|
37
|
-
re[:domain] = %r/\A#{domain}\z/o
|
38
|
-
|
39
|
-
return re
|
40
|
-
end
|
41
|
-
|
42
15
|
build_flatten_rfc822header_list = lambda do
|
43
|
-
# Convert HEADER: structured hash table to flatten hash table for being
|
44
|
-
# called from Sisimai::Lhost::*
|
16
|
+
# Convert HEADER: structured hash table to flatten hash table for being called from Sisimai::Lhost::*
|
45
17
|
fv = {}
|
46
18
|
HeaderTable.each_value do |e|
|
47
19
|
e.each { |ee| fv[ee] = true }
|
48
20
|
end
|
49
21
|
return fv
|
50
22
|
end
|
51
|
-
|
52
|
-
Re = build_regular_expressions.call
|
53
23
|
HeaderIndex = build_flatten_rfc822header_list.call
|
54
24
|
|
25
|
+
def FIELDINDEX
|
26
|
+
return %w[
|
27
|
+
Resent-Date From Sender Reply-To To Message-ID Subject Return-Path Received Date X-Mailer
|
28
|
+
Content-Type Content-Transfer-Encoding Content-Description Content-Disposition
|
29
|
+
]
|
30
|
+
# The following fields are not referred in Sisimai
|
31
|
+
# Resent-From Resent-Sender Resent-Cc Cc Bcc Resent-Bcc In-Reply-To References
|
32
|
+
# Comments Keywords
|
33
|
+
end
|
34
|
+
|
55
35
|
# Grouped RFC822 headers
|
56
36
|
# @param [Symbol] group RFC822 Header group name
|
57
37
|
# @return [Array,Hash] RFC822 Header list
|
@@ -67,66 +47,37 @@ module Sisimai
|
|
67
47
|
return { 'to' => true, 'from' => true, 'subject' => true, 'message-id' => true }
|
68
48
|
end
|
69
49
|
|
70
|
-
# Check that the argument is an email address or not
|
71
|
-
# @param [String] email Email address string
|
72
|
-
# @return [True,False] true: is an email address
|
73
|
-
# false: is not an email address
|
74
|
-
def is_emailaddress(email)
|
75
|
-
return false unless email.is_a?(::String)
|
76
|
-
return false if email =~ %r/(?:[\x00-\x1f]|\x1f)/
|
77
|
-
return false if email.size > 254
|
78
|
-
return true if email =~ Re[:ignored]
|
79
|
-
return false
|
80
|
-
end
|
81
|
-
|
82
|
-
# Check that the argument is mailer-daemon or not
|
83
|
-
# @param [String] email Email address
|
84
|
-
# @return [True,False] true: mailer-daemon
|
85
|
-
# false: Not mailer-daemon
|
86
|
-
def is_mailerdaemon(email)
|
87
|
-
return false unless email.is_a?(::String)
|
88
|
-
regex = %r/(?:
|
89
|
-
(?:mailer-daemon|postmaster)[@]
|
90
|
-
|[<(](?:mailer-daemon|postmaster)[)>]
|
91
|
-
|\A(?:mailer-daemon|postmaster)\z
|
92
|
-
|[ ]?mailer-daemon[ ]
|
93
|
-
)
|
94
|
-
/x.freeze
|
95
|
-
return true if email.downcase =~ regex
|
96
|
-
return false
|
97
|
-
end
|
98
|
-
|
99
50
|
# Convert Received headers to a structured data
|
100
|
-
# @param [String]
|
51
|
+
# @param [String] argv1 Received header
|
101
52
|
# @return [Array] Received header as a structured data
|
102
|
-
def received(
|
103
|
-
return [] unless
|
53
|
+
def received(argv1)
|
54
|
+
return [] unless argv1.is_a?(::String)
|
104
55
|
|
105
56
|
hosts = []
|
106
57
|
value = { 'from' => '', 'by' => '' }
|
107
58
|
|
108
59
|
# Received: (qmail 10000 invoked by uid 999); 24 Apr 2013 00:00:00 +0900
|
109
|
-
return [] if
|
60
|
+
return [] if argv1.include?('(qmail ') && argv1.include?(' invoked ')
|
61
|
+
|
62
|
+
p1 = argv1.index('from ') || -1
|
63
|
+
p2 = argv1.index('by ') || -1
|
64
|
+
p3 = argv1.index(' ', p2 + 3) || -1
|
110
65
|
|
111
|
-
if
|
112
|
-
# Received: from localhost (localhost)
|
113
|
-
# by nijo.example.jp (V8/cf) id s1QB5ma0018057;
|
66
|
+
if p1 == 0 && p2 > 1 && p2 < p3
|
67
|
+
# Received: from localhost (localhost) by nijo.example.jp (V8/cf) id s1QB5ma0018057;
|
114
68
|
# Wed, 26 Feb 2014 06:05:48 -0500
|
115
|
-
value['from'] =
|
116
|
-
value['by'] =
|
117
|
-
|
118
|
-
elsif
|
119
|
-
# Received: by 10.70.22.98 with SMTP id c2mr1838265pdf.3; Fri, 18 Jul 2014
|
120
|
-
|
121
|
-
value['
|
122
|
-
value['by'] = cr[1]
|
69
|
+
value['from'] = Sisimai::String.sweep(argv1[p1 + 5, p2 - p1 - 5])
|
70
|
+
value['by'] = Sisimai::String.sweep(argv1[p2 + 3, p3 - p2 - 3])
|
71
|
+
|
72
|
+
elsif p1 != 0 && p2 > -1
|
73
|
+
# Received: by 10.70.22.98 with SMTP id c2mr1838265pdf.3; Fri, 18 Jul 2014 00:31:02 -0700 (PDT)
|
74
|
+
value['from'] = Sisimai::String.sweep(argv1[p2 + 3, argv1.size])
|
75
|
+
value['by'] = Sisimai::String.sweep(argv1[p2 + 3, p3 - p2 - 3])
|
123
76
|
end
|
124
77
|
|
125
78
|
if value['from'].include?(' ')
|
126
|
-
# Received: from [10.22.22.222] (smtp
|
127
|
-
# (
|
128
|
-
# by nijo.example.jp (V8/cf) with ESMTP id s1QB5ka0018055;
|
129
|
-
# Wed, 26 Feb 2014 06:05:47 -0500
|
79
|
+
# Received: from [10.22.22.222] (smtp.kyoto.ocn.ne.jp [192.0.2.222]) (authenticated bits=0)
|
80
|
+
# by nijo.example.jp (V8/cf) with ESMTP id s1QB5ka0018055; Wed, 26 Feb 2014 06:05:47 -0500
|
130
81
|
received = value['from'].split(' ')
|
131
82
|
namelist = []
|
132
83
|
addrlist = []
|
@@ -135,13 +86,13 @@ module Sisimai
|
|
135
86
|
|
136
87
|
while e = received.shift do
|
137
88
|
# Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222])
|
138
|
-
|
89
|
+
cv = Sisimai::String.ipv4(e) || []
|
90
|
+
if cv.size > 0
|
139
91
|
# [192.0.2.1] or (192.0.2.1)
|
140
|
-
|
141
|
-
addrlist << e
|
92
|
+
addrlist.append(*cv)
|
142
93
|
else
|
143
94
|
# hostname
|
144
|
-
e = e.delete('()')
|
95
|
+
e = e.delete('()').strip
|
145
96
|
namelist << e
|
146
97
|
end
|
147
98
|
end
|
@@ -176,31 +127,55 @@ module Sisimai
|
|
176
127
|
return hosts
|
177
128
|
end
|
178
129
|
|
179
|
-
# Split given entire message body into error message lines and the original
|
180
|
-
#
|
181
|
-
# @param [String]
|
182
|
-
# @param [
|
183
|
-
#
|
130
|
+
# Split given entire message body into error message lines and the original message part only
|
131
|
+
# include email headers
|
132
|
+
# @param [String] email Entire message body
|
133
|
+
# @param [Array] cutby List of strings which is a boundary of the original message part
|
134
|
+
# @param [Bool] keeps Flag for keeping strings after "\n\n"
|
184
135
|
# @return [Array] [Error message lines, The original message]
|
185
|
-
# @since
|
186
|
-
def
|
187
|
-
return nil if
|
188
|
-
return nil
|
136
|
+
# @since v5.0.0
|
137
|
+
def part(email = '', cutby = [], keeps = false)
|
138
|
+
return nil if email.empty?
|
139
|
+
return nil if cutby.empty?
|
140
|
+
|
141
|
+
boundaryor = '' # A boundary string divides the error message part and the original message part
|
142
|
+
positionor = nil # A Position of the boundary string
|
143
|
+
formerpart = '' # The error message part
|
144
|
+
latterpart = '' # The original message part
|
145
|
+
|
146
|
+
cutby.each do |e|
|
147
|
+
# Find a boundary string(2nd argument) from the 1st argument
|
148
|
+
positionor = email.index(e); next unless positionor
|
149
|
+
boundaryor = e
|
150
|
+
break
|
151
|
+
end
|
189
152
|
|
190
|
-
|
191
|
-
|
153
|
+
if positionor
|
154
|
+
# There is the boundary string in the message body
|
155
|
+
formerpart = email[0, positionor]
|
156
|
+
latterpart = email[positionor + boundaryor.size + 1, email.size - positionor]
|
157
|
+
else
|
158
|
+
# Substitute the entire message to the former part when the boundary string is not included
|
159
|
+
# the "email"
|
160
|
+
formerpart = email
|
161
|
+
latterpart = ''
|
162
|
+
end
|
192
163
|
|
193
|
-
|
164
|
+
if latterpart.size > 0
|
194
165
|
# Remove blank lines, the message body of the original message, and append "\n" at the end
|
195
166
|
# of the original message headers
|
196
167
|
# 1. Remove leading blank lines
|
197
168
|
# 2. Remove text after the first blank line: \n\n
|
198
169
|
# 3. Append "\n" at the end of test block when the last character is not "\n"
|
199
|
-
|
200
|
-
|
201
|
-
|
170
|
+
latterpart.sub!(/\A[\r\n\s]+/, '')
|
171
|
+
if keeps == false
|
172
|
+
# Remove text after the first blank line: \n\n when "keeps" is false
|
173
|
+
latterpart = latterpart[0, latterpart.index("\n\n")] if latterpart.include?("\n\n")
|
174
|
+
end
|
175
|
+
latterpart << "\n" unless latterpart.end_with?("\n")
|
202
176
|
end
|
203
|
-
|
177
|
+
|
178
|
+
return [formerpart, latterpart]
|
204
179
|
end
|
205
180
|
|
206
181
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sisimai
|
2
|
+
# Sisimai::RFC5965 - A class for An Extensible Format for Email Feedback Reports
|
3
|
+
module RFC5965
|
4
|
+
class << self
|
5
|
+
# https://datatracker.ietf.org/doc/html/rfc5965
|
6
|
+
def FIELDINDEX
|
7
|
+
return [
|
8
|
+
# Required Fields
|
9
|
+
# The following report header fields MUST appear exactly once:
|
10
|
+
'Feedback-Type', 'User-Agent', 'Version',
|
11
|
+
|
12
|
+
# Optional Fields Appearing Once
|
13
|
+
# The following header fields are optional and MUST NOT appear more than once:
|
14
|
+
# - "Reporting-MTA" is defined in Sisimai::RFC1894->FIELDINDEX()
|
15
|
+
'Original-Envelope-Id', 'Original-Mail-From', 'Arrival-Date', 'Source-IP', 'Incidents',
|
16
|
+
|
17
|
+
# Optional Fields Appearing Multiple Times
|
18
|
+
# The following set of header fields are optional and may appear any number of times as
|
19
|
+
# appropriate:
|
20
|
+
'Authentication-Results', 'Original-Rcpt-To', 'Reported-Domain', 'Reported-URI',
|
21
|
+
|
22
|
+
# The historic field "Received-Date" SHOULD also be accepted and interpreted identically
|
23
|
+
# to "Arrival-Date". However, if both are present, the report is malformed and SHOULD be
|
24
|
+
# treated as described in Section 4.
|
25
|
+
'Received-Date',
|
26
|
+
]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
data/lib/sisimai/rhost/cox.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module Sisimai
|
2
2
|
module Rhost
|
3
|
-
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::
|
4
|
-
#
|
5
|
-
#
|
3
|
+
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
|
4
|
+
# of get() method when the value of "destination" of the object is "charter.net". This class is
|
5
|
+
# called only Sisimai::Fact class.
|
6
6
|
module Cox
|
7
7
|
class << self
|
8
|
-
# Imported from p5-Sisimail/lib/Sisimai/Rhost/Cox.pm
|
9
8
|
ErrorCodes = {
|
10
9
|
# https://www.cox.com/residential/support/email-error-codes.html
|
11
10
|
'CXBL' => 'blocked', # The sending IP address has been blocked by Cox due to exhibiting spam-like behavior.
|
@@ -79,11 +78,11 @@ module Sisimai
|
|
79
78
|
}.freeze
|
80
79
|
|
81
80
|
# Detect bounce reason from https://cox.com/
|
82
|
-
# @param [Sisimai::
|
81
|
+
# @param [Sisimai::Fact] argvs Parsed email object
|
83
82
|
# @return [String, Nil] The bounce reason at Cox
|
84
83
|
# @since v4.25.8
|
85
84
|
def get(argvs)
|
86
|
-
statusmesg = argvs
|
85
|
+
statusmesg = argvs['diagnosticcode']
|
87
86
|
codenumber = 0
|
88
87
|
|
89
88
|
if cv = statusmesg.match(/AUP#([0-9A-Z]+)/)
|
@@ -1,12 +1,10 @@
|
|
1
1
|
module Sisimai
|
2
2
|
module Rhost
|
3
|
-
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::
|
4
|
-
#
|
5
|
-
# is
|
6
|
-
# This class is called only Sisimai::Data class.
|
3
|
+
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
|
4
|
+
# of get() method when the value of "rhost" of the object is "*.laposte.net" or "*.orange.fr".
|
5
|
+
# This class is called only Sisimai::Fact class.
|
7
6
|
module FrancePTT
|
8
7
|
class << self
|
9
|
-
# Imported from p5-Sisimail/lib/Sisimai/Rhost/FrancePTT.pm
|
10
8
|
ErrorCodes = {
|
11
9
|
# 550 5.7.1 Service unavailable; client [X.X.X.X] blocked using Spamhaus
|
12
10
|
# Les emails envoyes vers la messagerie Laposte.net ont ete bloques par nos services.
|
@@ -133,12 +131,12 @@ module Sisimai
|
|
133
131
|
}.freeze
|
134
132
|
|
135
133
|
# Detect bounce reason from Oranage or La Poste
|
136
|
-
# @param [Sisimai::
|
134
|
+
# @param [Sisimai::Fact] argvs Parsed email object
|
137
135
|
# @return [String] The bounce reason for Orange or La Poste
|
138
136
|
def get(argvs)
|
139
|
-
return argvs
|
137
|
+
return argvs['reason'] unless argvs['reason'].empty?
|
140
138
|
|
141
|
-
statusmesg = argvs
|
139
|
+
statusmesg = argvs['diagnosticcode']
|
142
140
|
reasontext = ''
|
143
141
|
|
144
142
|
if cv = statusmesg.match(/\b(LPN|LPNAAA|OFR|OUK)(_[0-9]{3}|[0-9]{3}[-_][0-9]{3})\b/i)
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Sisimai
|
2
2
|
module Rhost
|
3
|
-
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::
|
4
|
-
#
|
5
|
-
#
|
3
|
+
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
|
4
|
+
# of get() method when the value of "rhost" of the object is "*.secureserver.net". This class is
|
5
|
+
# called only Sisimai::Fact class.
|
6
6
|
module GoDaddy
|
7
7
|
class << self
|
8
|
-
# Imported from p5-Sisimail/lib/Sisimai/Rhost/GoDaddy.pm
|
9
8
|
# https://www.godaddy.com/help/what-does-my-email-bounceback-mean-3568
|
10
9
|
ErrorCodes = {
|
11
|
-
'IB103' => '
|
10
|
+
'IB103' => 'badreputation', # 554 Connection refused. This IP has a poor reputation on Cloudmark Sender Intelligence (CSI). IB103
|
12
11
|
'IB104' => 'blocked', # 554 Connection refused. This IP is listed on the Spamhaus Block List (SBL). IB104
|
13
12
|
'IB105' => 'blocked', # 554 Connection refused. This IP is listed on the Exploits Block List (XBL). IB105
|
14
13
|
'IB106' => 'blocked', # 554 Connection refused. This IP is listed on the Policy Block List (PBL). IB106
|
@@ -39,19 +38,19 @@ module Sisimai
|
|
39
38
|
}.freeze
|
40
39
|
|
41
40
|
# Detect bounce reason from GoDaddy
|
42
|
-
# @param [Sisimai::
|
41
|
+
# @param [Sisimai::Fact] argvs Parsed email object
|
43
42
|
# @return [String] The bounce reason for GoDaddy
|
44
43
|
# @see https://www.godaddy.com/help/what-does-my-email-bounceback-mean-3568
|
45
44
|
def get(argvs)
|
46
|
-
return argvs
|
45
|
+
return argvs['reason'] unless argvs['reason'].empty?
|
47
46
|
|
48
|
-
statusmesg = argvs
|
47
|
+
statusmesg = argvs['diagnosticcode']
|
48
|
+
positionib = statusmesg.index(' IB') || -1
|
49
49
|
reasontext = ''
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
else
|
51
|
+
# 192.0.2.22 has sent to too many recipients this hour. IB607 ...
|
52
|
+
reasontext = ErrorCodes[statusmesg[positionib + 1, 5]] || '' if positionib > 1
|
53
|
+
if reasontext.empty?
|
55
54
|
# 553 http://www.spamhaus.org/query/bl?ip=192.0.0.222
|
56
55
|
MessagesOf.each_key do |e|
|
57
56
|
MessagesOf[e].each do |f|
|
@@ -62,6 +61,7 @@ module Sisimai
|
|
62
61
|
break unless reasontext.empty?
|
63
62
|
end
|
64
63
|
end
|
64
|
+
|
65
65
|
return reasontext
|
66
66
|
end
|
67
67
|
|