sisimai 5.1.0 → 5.2.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/.github/workflows/rake-test.yml +1 -1
- data/ChangeLog.md +102 -0
- data/Makefile +4 -2
- data/README-JA.md +23 -16
- data/README.md +22 -15
- data/lib/sisimai/arf.rb +121 -210
- data/lib/sisimai/fact.rb +208 -158
- data/lib/sisimai/lda.rb +98 -0
- data/lib/sisimai/lhost/activehunter.rb +1 -1
- data/lib/sisimai/lhost/amazonses.rb +185 -301
- data/lib/sisimai/lhost/apachejames.rb +48 -51
- data/lib/sisimai/lhost/biglobe.rb +1 -2
- data/lib/sisimai/lhost/courier.rb +10 -8
- data/lib/sisimai/lhost/domino.rb +25 -25
- data/lib/sisimai/lhost/dragonfly.rb +3 -4
- data/lib/sisimai/lhost/einsundeins.rb +3 -4
- data/lib/sisimai/lhost/exchange2003.rb +6 -8
- data/lib/sisimai/lhost/exchange2007.rb +111 -101
- data/lib/sisimai/lhost/exim.rb +232 -242
- data/lib/sisimai/lhost/ezweb.rb +43 -51
- data/lib/sisimai/lhost/fml.rb +2 -3
- data/lib/sisimai/lhost/gmail.rb +32 -28
- data/lib/sisimai/lhost/gmx.rb +4 -16
- data/lib/sisimai/lhost/googlegroups.rb +9 -8
- data/lib/sisimai/lhost/googleworkspace.rb +94 -0
- data/lib/sisimai/lhost/imailserver.rb +7 -16
- data/lib/sisimai/lhost/interscanmss.rb +1 -1
- data/lib/sisimai/lhost/kddi.rb +3 -4
- data/lib/sisimai/lhost/mailfoundry.rb +2 -5
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +1 -2
- data/lib/sisimai/lhost/messagingserver.rb +14 -13
- data/lib/sisimai/lhost/mfilter.rb +4 -3
- data/lib/sisimai/lhost/notes.rb +2 -4
- data/lib/sisimai/lhost/opensmtpd.rb +2 -2
- data/lib/sisimai/lhost/postfix.rb +25 -27
- data/lib/sisimai/lhost/qmail.rb +130 -106
- data/lib/sisimai/lhost/sendmail.rb +19 -18
- data/lib/sisimai/lhost/v5sendmail.rb +88 -60
- data/lib/sisimai/lhost/verizon.rb +2 -2
- data/lib/sisimai/lhost/x1.rb +1 -1
- data/lib/sisimai/lhost/x2.rb +1 -2
- data/lib/sisimai/lhost/x3.rb +2 -2
- data/lib/sisimai/lhost/x6.rb +1 -1
- data/lib/sisimai/lhost/zoho.rb +2 -2
- data/lib/sisimai/lhost.rb +18 -21
- data/lib/sisimai/message.rb +93 -146
- data/lib/sisimai/order.rb +21 -77
- data/lib/sisimai/reason/authfailure.rb +1 -4
- data/lib/sisimai/reason/badreputation.rb +2 -2
- data/lib/sisimai/reason/blocked.rb +7 -10
- data/lib/sisimai/reason/contenterror.rb +7 -1
- data/lib/sisimai/reason/exceedlimit.rb +1 -4
- data/lib/sisimai/reason/failedstarttls.rb +42 -0
- data/lib/sisimai/reason/filtered.rb +5 -4
- data/lib/sisimai/reason/hasmoved.rb +1 -2
- data/lib/sisimai/reason/hostunknown.rb +3 -3
- data/lib/sisimai/reason/mailboxfull.rb +2 -4
- data/lib/sisimai/reason/mailererror.rb +1 -2
- data/lib/sisimai/reason/mesgtoobig.rb +2 -4
- data/lib/sisimai/reason/norelaying.rb +2 -3
- data/lib/sisimai/reason/notaccept.rb +2 -3
- data/lib/sisimai/reason/notcompliantrfc.rb +10 -4
- data/lib/sisimai/reason/rejected.rb +1 -1
- data/lib/sisimai/reason/requireptr.rb +2 -2
- data/lib/sisimai/reason/securityerror.rb +1 -3
- data/lib/sisimai/reason/spamdetected.rb +6 -8
- data/lib/sisimai/reason/speeding.rb +1 -2
- data/lib/sisimai/reason/suppressed.rb +36 -0
- data/lib/sisimai/reason/suspend.rb +1 -3
- data/lib/sisimai/reason/systemerror.rb +5 -0
- data/lib/sisimai/reason/toomanyconn.rb +1 -2
- data/lib/sisimai/reason/userunknown.rb +1 -1
- data/lib/sisimai/reason/virusdetected.rb +5 -6
- data/lib/sisimai/reason.rb +77 -73
- data/lib/sisimai/rfc1123.rb +152 -0
- data/lib/sisimai/rfc1894.rb +102 -62
- data/lib/sisimai/rfc2045.rb +2 -1
- data/lib/sisimai/rfc3464/thirdparty.rb +102 -0
- data/lib/sisimai/rfc3464.rb +222 -343
- data/lib/sisimai/rfc3834.rb +1 -1
- data/lib/sisimai/rfc5322.rb +7 -17
- data/lib/sisimai/rfc791.rb +69 -0
- data/lib/sisimai/rhost/aol.rb +36 -0
- data/lib/sisimai/rhost/apple.rb +5 -2
- data/lib/sisimai/rhost/cox.rb +3 -2
- data/lib/sisimai/rhost/facebook.rb +100 -0
- data/lib/sisimai/rhost/franceptt.rb +3 -2
- data/lib/sisimai/rhost/godaddy.rb +3 -2
- data/lib/sisimai/rhost/google.rb +19 -17
- data/lib/sisimai/rhost/gsuite.rb +42 -0
- data/lib/sisimai/rhost/iua.rb +3 -3
- data/lib/sisimai/rhost/kddi.rb +3 -2
- data/lib/sisimai/rhost/messagelabs.rb +37 -0
- data/lib/sisimai/rhost/microsoft.rb +56 -49
- data/lib/sisimai/rhost/mimecast.rb +29 -27
- data/lib/sisimai/rhost/nttdocomo.rb +4 -3
- data/lib/sisimai/rhost/outlook.rb +36 -0
- data/lib/sisimai/rhost/spectrum.rb +3 -2
- data/lib/sisimai/rhost/tencent.rb +3 -2
- data/lib/sisimai/rhost/yahooinc.rb +4 -3
- data/lib/sisimai/rhost.rb +69 -39
- data/lib/sisimai/smtp/command.rb +31 -21
- data/lib/sisimai/smtp/failure.rb +103 -0
- data/lib/sisimai/smtp/reply.rb +29 -25
- data/lib/sisimai/smtp/status.rb +36 -19
- data/lib/sisimai/smtp/transcript.rb +15 -15
- data/lib/sisimai/string.rb +0 -46
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/maildir/bsd/lhost-postfix-30.eml +81 -81
- data/set-of-emails/maildir/bsd/{lhost-aol-03.eml → rhost-aol-03.eml} +1264 -1264
- data/set-of-emails/maildir/bsd/{lhost-aol-04.eml → rhost-aol-04.eml} +1260 -1260
- data/set-of-emails/maildir/bsd/{lhost-aol-05.eml → rhost-aol-05.eml} +105 -105
- data/set-of-emails/maildir/bsd/{lhost-aol-06.eml → rhost-aol-06.eml} +105 -105
- data/set-of-emails/maildir/bsd/rhost-gsuite-01.eml +189 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-02.eml +180 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-03.eml +251 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-04.eml +211 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-05.eml +226 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-06.eml +257 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-07.eml +289 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-08.eml +231 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-09.eml +231 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-10.eml +254 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-11.eml +228 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-12.eml +271 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-13.eml +261 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-14.eml +273 -0
- data/set-of-emails/maildir/bsd/rhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/{lhost-messagelabs-01.eml → rhost-messagelabs-01.eml} +93 -93
- data/set-of-emails/maildir/bsd/rhost-outlook-01.eml +72 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-02.eml +72 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-03.eml +72 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-04.eml +79 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-06.eml +75 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-07.eml +70 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-08.eml +70 -0
- data/set-of-emails/maildir/bsd/rhost-outlook-09.eml +56 -0
- data/set-of-emails/maildir/tmp/arf-22.eml +49 -0
- data/set-of-emails/maildir/tmp/arf-23.eml +49 -0
- data/set-of-emails/maildir/tmp/arf-24.eml +50 -0
- data/set-of-emails/maildir/tmp/lhost-exim-07.eml +28 -0
- metadata +73 -56
- data/lib/sisimai/lhost/amavis.rb +0 -163
- data/lib/sisimai/lhost/amazonworkmail.rb +0 -127
- data/lib/sisimai/lhost/aol.rb +0 -125
- data/lib/sisimai/lhost/barracuda.rb +0 -92
- data/lib/sisimai/lhost/bigfoot.rb +0 -125
- data/lib/sisimai/lhost/facebook.rb +0 -188
- data/lib/sisimai/lhost/gsuite.rb +0 -194
- data/lib/sisimai/lhost/mailru.rb +0 -214
- data/lib/sisimai/lhost/mcafee.rb +0 -109
- data/lib/sisimai/lhost/messagelabs.rb +0 -120
- data/lib/sisimai/lhost/mxlogic.rb +0 -198
- data/lib/sisimai/lhost/office365.rb +0 -252
- data/lib/sisimai/lhost/outlook.rb +0 -129
- data/lib/sisimai/lhost/powermta.rb +0 -118
- data/lib/sisimai/lhost/receivingses.rb +0 -126
- data/lib/sisimai/lhost/sendgrid.rb +0 -150
- data/lib/sisimai/lhost/surfcontrol.rb +0 -105
- data/lib/sisimai/lhost/x4.rb +0 -269
- data/lib/sisimai/lhost/x5.rb +0 -112
- data/lib/sisimai/lhost/yahoo.rb +0 -102
- data/lib/sisimai/lhost/yandex.rb +0 -118
- data/lib/sisimai/mda.rb +0 -121
- data/lib/sisimai/smtp/error.rb +0 -119
- /data/set-of-emails/maildir/bsd/{lhost-googlegroups-15.eml → lhost-googleworkspace-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-x4-08.eml → lhost-x2-06.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-01.eml → rfc3464-51.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-03.eml → rfc3464-52.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-04.eml → rfc3464-53.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-05.eml → rfc3464-54.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-06.eml → rfc3464-55.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-07.eml → rfc3464-56.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-08.eml → rfc3464-57.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-09.eml → rfc3464-58.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-10.eml → rfc3464-59.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-11.eml → rfc3464-60.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-12.eml → rfc3464-61.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-13.eml → rfc3464-62.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-14.eml → rfc3464-63.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-15.eml → rfc3464-64.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-gsuite-02.eml → rfc3464-65.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-aol-01.eml → rhost-aol-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-aol-02.eml → rhost-aol-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-facebook-03.eml → rhost-facebook-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-facebook-04.eml → rhost-facebook-04.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-messagelabs-02.eml → rhost-messagelabs-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-messagelabs-03.eml → rhost-messagelabs-03.eml} +0 -0
- /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-37.eml +0 -0
- /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-38.eml +0 -0
- /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-39.eml +0 -0
data/lib/sisimai/lhost/gsuite.rb
DELETED
@@ -1,194 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::GSuite decodes a bounce email which created by Google Workspace https://workspace.google.com/.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module GSuite
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'].freeze
|
10
|
-
MarkingsOf = {
|
11
|
-
message: ['** '],
|
12
|
-
error: ['The response was:', 'The response from the remote server was:'],
|
13
|
-
}.freeze
|
14
|
-
MessagesOf = {
|
15
|
-
'userunknown' => ["because the address couldn't be found. Check for typos or unnecessary spaces and try again."],
|
16
|
-
'notaccept' => ['Null MX'],
|
17
|
-
'networkerror' => [' had no relevant answers.', ' responded with code NXDOMAIN'],
|
18
|
-
}.freeze
|
19
|
-
|
20
|
-
# @abstract Decodes the bounce message from G Suite (Transfer from G Suite to a destinaion host)
|
21
|
-
# @param [Hash] mhead Message headers of a bounce email
|
22
|
-
# @param [String] mbody Message body of a bounce email
|
23
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
24
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
25
|
-
def inquire(mhead, mbody)
|
26
|
-
return nil unless mhead['from'].end_with?('<mailer-daemon@googlemail.com>')
|
27
|
-
return nil unless mhead['subject'].start_with?('Delivery Status Notification')
|
28
|
-
return nil unless mhead['x-gm-message-state']
|
29
|
-
|
30
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
31
|
-
permessage = {} # (Hash) Store values of each Per-Message field
|
32
|
-
|
33
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
34
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
35
|
-
bodyslices = emailparts[0].split("\n")
|
36
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
37
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
38
|
-
endoferror = false # (Integer) Flag for a blank line after error messages
|
39
|
-
anotherset = {} # (Hash) Another error information
|
40
|
-
emptylines = 0 # (Integer) The number of empty lines
|
41
|
-
v = nil
|
42
|
-
|
43
|
-
while e = bodyslices.shift do
|
44
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
45
|
-
# line of the beginning of the original message.
|
46
|
-
if readcursor == 0
|
47
|
-
# Beginning of the bounce message or message/delivery-status part
|
48
|
-
readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.start_with?(a) }
|
49
|
-
end
|
50
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
51
|
-
|
52
|
-
if f = Sisimai::RFC1894.match(e)
|
53
|
-
# "e" matched with any field defined in RFC3464
|
54
|
-
next unless o = Sisimai::RFC1894.field(e)
|
55
|
-
v = dscontents[-1]
|
56
|
-
|
57
|
-
if o[-1] == 'addr'
|
58
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
59
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
60
|
-
if o[0] == 'final-recipient'
|
61
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
62
|
-
if v['recipient']
|
63
|
-
# There are multiple recipient addresses in the message body.
|
64
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
65
|
-
v = dscontents[-1]
|
66
|
-
end
|
67
|
-
v['recipient'] = o[2]
|
68
|
-
recipients += 1
|
69
|
-
else
|
70
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
71
|
-
v['alias'] = o[2]
|
72
|
-
end
|
73
|
-
elsif o[-1] == 'code'
|
74
|
-
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
75
|
-
v['spec'] = o[1]
|
76
|
-
v['diagnosis'] = o[2]
|
77
|
-
else
|
78
|
-
# Other DSN fields defined in RFC3464
|
79
|
-
next unless fieldtable[o[0]]
|
80
|
-
v[fieldtable[o[0]]] = o[2]
|
81
|
-
|
82
|
-
if fieldtable[o[0]] == 'lhost'
|
83
|
-
# Do not set an email address as a hostname in "lhost" value
|
84
|
-
v['lhost'] = '' if v['lhost'].include?('@')
|
85
|
-
end
|
86
|
-
|
87
|
-
next unless f
|
88
|
-
permessage[fieldtable[o[0]]] = o[2]
|
89
|
-
end
|
90
|
-
else
|
91
|
-
# The line does not begin with a DSN field defined in RFC3464 Append error messages continued
|
92
|
-
# from the previous line
|
93
|
-
if endoferror == false && v && ! v['diagnosis'].to_s.empty?
|
94
|
-
endoferror ||= true if e.empty?
|
95
|
-
|
96
|
-
next if endoferror
|
97
|
-
next unless e.start_with?(' ')
|
98
|
-
v['diagnosis'] << e
|
99
|
-
|
100
|
-
elsif MarkingsOf[:error].any? { |a| e.start_with?(a) }
|
101
|
-
# Detect SMTP session error or connection error
|
102
|
-
# The response from the remote server was:
|
103
|
-
anotherset['diagnosis'] << ' ' << e
|
104
|
-
else
|
105
|
-
# ** Address not found **
|
106
|
-
#
|
107
|
-
# Your message wasn't delivered to * because the address couldn't be found.
|
108
|
-
# Check for typos or unnecessary spaces and try again.
|
109
|
-
#
|
110
|
-
# The response from the remote server was:
|
111
|
-
# 550 #5.1.0 Address rejected.
|
112
|
-
next if e.start_with?('Content-Type:')
|
113
|
-
if anotherset['diagnosis']
|
114
|
-
# Continued error messages from the previous line like "550 #5.1.0 Address rejected."
|
115
|
-
next if emptylines > 5
|
116
|
-
if e.empty?
|
117
|
-
# Count and next()
|
118
|
-
emptylines += 1
|
119
|
-
next
|
120
|
-
end
|
121
|
-
anotherset['diagnosis'] << ' ' << e
|
122
|
-
else
|
123
|
-
# ** Address not found **
|
124
|
-
#
|
125
|
-
# Your message wasn't delivered to * because the address couldn't be found.
|
126
|
-
# Check for typos or unnecessary spaces and try again.
|
127
|
-
next if e.empty?
|
128
|
-
next unless MarkingsOf[:message].any? { |a| e.start_with?(a) }
|
129
|
-
anotherset['diagnosis'] = e
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
return nil unless recipients > 0
|
135
|
-
|
136
|
-
dscontents.each do |e|
|
137
|
-
# Set default values if each value is empty.
|
138
|
-
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
139
|
-
|
140
|
-
if anotherset['diagnosis']
|
141
|
-
# Copy alternative error message
|
142
|
-
e['diagnosis'] = anotherset['diagnosis'] unless e['diagnosis']
|
143
|
-
|
144
|
-
if e['diagnosis'].include?(' ') == false && e['diagnosis'].to_i > 0
|
145
|
-
e['diagnosis'] = anotherset['diagnosis']
|
146
|
-
else
|
147
|
-
# More detailed error message is in "anotherset"
|
148
|
-
as = nil # status
|
149
|
-
ar = nil # replycode
|
150
|
-
|
151
|
-
e['status'] ||= ''
|
152
|
-
e['replycode'] ||= ''
|
153
|
-
|
154
|
-
if e['status'] == '' || e['status'].start_with?('4.0.0', '5.0.0')
|
155
|
-
# Check the value of D.S.N. in anotherset
|
156
|
-
as = Sisimai::SMTP::Status.find(anotherset['diagnosis'])
|
157
|
-
if as && as[-3, 3] != '0.0'
|
158
|
-
# The D.S.N. is neither an empty nor *.0.0
|
159
|
-
e['status'] = as
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
if e['replycode'].empty? || e['replycode'].start_with?('400', '500')
|
164
|
-
# Check the value of SMTP reply code in anotherset
|
165
|
-
ar = Sisimai::SMTP::Reply.find(anotherset['diagnosis'])
|
166
|
-
if ar && ar[-2, 2].to_i != 0
|
167
|
-
# The SMTP reply code is neither an empty nor *00
|
168
|
-
e['replycode'] = ar
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
if (as || ar) && (anotherset['diagnosis'].size > e['diagnosis'].size)
|
173
|
-
# Update the error message in e['diagnosis']
|
174
|
-
e['diagnosis'] = anotherset['diagnosis']
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
180
|
-
MessagesOf.each_key do |r|
|
181
|
-
# Guess an reason of the bounce
|
182
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
183
|
-
e['reason'] = r
|
184
|
-
break
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
189
|
-
end
|
190
|
-
def description; return 'G Suite: https://gsuite.google.com'; end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
data/lib/sisimai/lhost/mailru.rb
DELETED
@@ -1,214 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MailRu decodes a bounce email which created by @mail.ru https://mail.ru/.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module MailRu
|
5
|
-
class << self
|
6
|
-
# Based on Sisimai::Lhost::Exim
|
7
|
-
require 'sisimai/lhost'
|
8
|
-
|
9
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
Boundaries = ['------ This is a copy of the message, including all the headers. ------'].freeze
|
11
|
-
StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
|
12
|
-
ReCommands = [
|
13
|
-
%r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
|
14
|
-
%r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
|
15
|
-
].freeze
|
16
|
-
MessagesOf = {
|
17
|
-
'expired' => [
|
18
|
-
'retry timeout exceeded',
|
19
|
-
'No action is required on your part',
|
20
|
-
],
|
21
|
-
'userunknown' => ['user not found'],
|
22
|
-
'hostunknown' => [
|
23
|
-
'all host address lookups failed permanently',
|
24
|
-
'all relevant MX records point to non-existent hosts',
|
25
|
-
'Unrouteable address',
|
26
|
-
],
|
27
|
-
'mailboxfull' => ['mailbox is full', 'error: quota exceed'],
|
28
|
-
'notaccept' => [
|
29
|
-
'an MX or SRV record indicated no SMTP service',
|
30
|
-
'no host found for existing SMTP connection',
|
31
|
-
],
|
32
|
-
'syntaxerror' => [
|
33
|
-
'angle-brackets nested too deep',
|
34
|
-
'expected word or "<"',
|
35
|
-
'domain missing in source-routed address',
|
36
|
-
'malformed address:',
|
37
|
-
],
|
38
|
-
'systemerror' => [
|
39
|
-
'delivery to file forbidden',
|
40
|
-
'delivery to pipe forbidden',
|
41
|
-
'local delivery failed',
|
42
|
-
'LMTP error after ',
|
43
|
-
],
|
44
|
-
'contenterror' => ['Too many "Received" headers'],
|
45
|
-
}.freeze
|
46
|
-
|
47
|
-
# @abstract Decodes the bounce message from @mail.ru
|
48
|
-
# @param [Hash] mhead Message headers of a bounce email
|
49
|
-
# @param [String] mbody Message body of a bounce email
|
50
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
51
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
52
|
-
def inquire(mhead, mbody)
|
53
|
-
mfrom = mhead['from'].downcase
|
54
|
-
msgid = mhead['message-id'] ? mhead['message-id'].downcase : ''
|
55
|
-
match = 0
|
56
|
-
match += 1 if mfrom.include?('mailer-daemon@') && mfrom.include?('mail.ru')
|
57
|
-
match += 1 if msgid.end_with?('.mail.ru>', 'smailru.net>')
|
58
|
-
match += 1 if [
|
59
|
-
'Delivery Status Notification',
|
60
|
-
'Mail delivery failed',
|
61
|
-
'Mail failure',
|
62
|
-
'Message frozen',
|
63
|
-
'Warning: message ',
|
64
|
-
'error(s) in forwarding or filtering'].any? { |a| mhead['subject'].include?(a) }
|
65
|
-
return nil unless match > 2
|
66
|
-
|
67
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
68
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
69
|
-
bodyslices = emailparts[0].split("\n")
|
70
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
71
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
72
|
-
v = nil
|
73
|
-
|
74
|
-
while e = bodyslices.shift do
|
75
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
76
|
-
# line of the beginning of the original message.
|
77
|
-
if readcursor == 0
|
78
|
-
# Beginning of the bounce message or delivery status part
|
79
|
-
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
80
|
-
next
|
81
|
-
end
|
82
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
83
|
-
next if e.empty?
|
84
|
-
|
85
|
-
# Это письмо создано автоматически
|
86
|
-
# сервером Mail.Ru, # отвечать на него не
|
87
|
-
# нужно.
|
88
|
-
#
|
89
|
-
# К сожалению, Ваше письмо не может
|
90
|
-
# быть# доставлено одному или нескольким
|
91
|
-
# получателям:
|
92
|
-
#
|
93
|
-
# **********************
|
94
|
-
#
|
95
|
-
# This message was created automatically by mail delivery software.
|
96
|
-
#
|
97
|
-
# A message that you sent could not be delivered to one or more of its
|
98
|
-
# recipients. This is a permanent error. The following address(es) failed:
|
99
|
-
#
|
100
|
-
# kijitora@example.jp
|
101
|
-
# SMTP error from remote mail server after RCPT TO:<kijitora@example.jp>:
|
102
|
-
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
103
|
-
v = dscontents[-1]
|
104
|
-
|
105
|
-
if e.start_with?(' ') && e.include?(' ') == false && e.index('@') > 1
|
106
|
-
# kijitora@example.jp
|
107
|
-
if v['recipient']
|
108
|
-
# There are multiple recipient addresses in the message body.
|
109
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
110
|
-
v = dscontents[-1]
|
111
|
-
end
|
112
|
-
v['recipient'] = e[2, e.size]
|
113
|
-
recipients += 1
|
114
|
-
|
115
|
-
elsif dscontents.size == recipients
|
116
|
-
# Error message
|
117
|
-
next if e.empty?
|
118
|
-
v['diagnosis'] ||= ''
|
119
|
-
v['diagnosis'] << e + ' '
|
120
|
-
else
|
121
|
-
# Error message when email address above does not include '@'
|
122
|
-
# and domain part.
|
123
|
-
next unless e.start_with?(' ')
|
124
|
-
v['alterrors'] ||= ''
|
125
|
-
v['alterrors'] << e + ' '
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
unless recipients > 0
|
130
|
-
# Fallback for getting recipient addresses
|
131
|
-
if mhead['x-failed-recipients']
|
132
|
-
# X-Failed-Recipients: kijitora@example.jp
|
133
|
-
rcptinhead = mhead['x-failed-recipients'].split(',')
|
134
|
-
rcptinhead.each { |a| a.delete(' ') }
|
135
|
-
recipients = rcptinhead.size
|
136
|
-
|
137
|
-
while e = rcptinhead.shift do
|
138
|
-
# Insert each recipient address into dscontents
|
139
|
-
dscontents[-1]['recipient'] = e
|
140
|
-
next if dscontents.size == recipients
|
141
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
return nil unless recipients > 0
|
146
|
-
|
147
|
-
# Get the name of the local MTA
|
148
|
-
# Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
|
149
|
-
receivedby = mhead['received'] || []
|
150
|
-
recvdtoken = Sisimai::RFC5322.received(receivedby[-1])
|
151
|
-
|
152
|
-
dscontents.each do |e|
|
153
|
-
# Check the error message, the rhost, the lhost, and the smtp command.
|
154
|
-
unless e['alterrors'].to_s.empty?
|
155
|
-
# Copy alternative error message
|
156
|
-
e['diagnosis'] ||= e['alterrors']
|
157
|
-
if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
|
158
|
-
# Override the value of diagnostic code message
|
159
|
-
e['diagnosis'] = e['alterrors'] unless e['alterrors'].empty?
|
160
|
-
end
|
161
|
-
e.delete('alterrors')
|
162
|
-
end
|
163
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
164
|
-
p1 = e['diagnosis'].rindex('__') || -1
|
165
|
-
e['diagnosis'] = e['diagnosis'][0, p1 - 1] if p1 > 2
|
166
|
-
|
167
|
-
unless e['rhost']
|
168
|
-
# Get the remote host name
|
169
|
-
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
170
|
-
p1 = e['diagnosis'].index('host ') || -1
|
171
|
-
p2 = e['diagnosis'].index(' ', p1 + 5) || -1
|
172
|
-
e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
|
173
|
-
e['rhost'] ||= recvdtoken[1]
|
174
|
-
end
|
175
|
-
e['lhost'] ||= recvdtoken[0]
|
176
|
-
|
177
|
-
unless e['command']
|
178
|
-
# Get the SMTP command name for the session
|
179
|
-
ReCommands.each do |r|
|
180
|
-
# Verify each regular expression of SMTP commands
|
181
|
-
if cv = e['diagnosis'].match(r)
|
182
|
-
e['command'] = cv[1].upcase
|
183
|
-
break
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# Detect the reason of bounce
|
188
|
-
if %w[HELO EHLO].index(e['command'])
|
189
|
-
# HELO | Connected to 192.0.2.135 but my name was rejected.
|
190
|
-
e['reason'] = 'blocked'
|
191
|
-
|
192
|
-
elsif e['command'] == 'MAIL'
|
193
|
-
# MAIL | Connected to 192.0.2.135 but sender was rejected.
|
194
|
-
e['reason'] = 'rejected'
|
195
|
-
else
|
196
|
-
# Verify each regular expression of session errors
|
197
|
-
MessagesOf.each_key do |r|
|
198
|
-
# Check each regular expression
|
199
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
200
|
-
e['reason'] = r
|
201
|
-
break
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
e['command'] ||= ''
|
206
|
-
end
|
207
|
-
|
208
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
209
|
-
end
|
210
|
-
def description; return '@mail.ru: https://mail.ru'; end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
data/lib/sisimai/lhost/mcafee.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::McAfee decodes a bounce email which created by McAfee Email Appliance.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module McAfee
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: message/rfc822'].freeze
|
10
|
-
StartingOf = { message: ['--- The following addresses had delivery problems ---'] }.freeze
|
11
|
-
MessagesOf = { 'userunknown' => [' User not exist', ' unknown.', '550 Unknown user ', 'No such user'] }.freeze
|
12
|
-
|
13
|
-
# @abstract Decodes the bounce message from McAfee Email Appliance
|
14
|
-
# @param [Hash] mhead Message headers of a bounce email
|
15
|
-
# @param [String] mbody Message body of a bounce email
|
16
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
17
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
18
|
-
def inquire(mhead, mbody)
|
19
|
-
# X-NAI-Header: Modified by McAfee Email and Web Security Virtual Appliance
|
20
|
-
return nil unless mhead['x-nai-header']
|
21
|
-
return nil unless mhead['x-nai-header'].start_with?('Modified by McAfee ')
|
22
|
-
return nil unless mhead['subject'] == 'Delivery Status'
|
23
|
-
|
24
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
25
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
26
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
|
-
bodyslices = emailparts[0].split("\n")
|
28
|
-
readslices = ['']
|
29
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
30
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
31
|
-
issuedcode = '' # (String) Alternative diagnostic message
|
32
|
-
v = nil
|
33
|
-
|
34
|
-
while e = bodyslices.shift do
|
35
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
36
|
-
# line of the beginning of the original message.
|
37
|
-
readslices << e # Save the current line for the next loop
|
38
|
-
|
39
|
-
if readcursor == 0
|
40
|
-
# Beginning of the bounce message or delivery status part
|
41
|
-
readcursor |= Indicators[:deliverystatus] if e.include?(StartingOf[:message][0])
|
42
|
-
next
|
43
|
-
end
|
44
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
45
|
-
next if e.empty?
|
46
|
-
|
47
|
-
# Content-Type: text/plain; name="deliveryproblems.txt"
|
48
|
-
#
|
49
|
-
# --- The following addresses had delivery problems ---
|
50
|
-
#
|
51
|
-
# <user@example.com> (User unknown user@example.com)
|
52
|
-
#
|
53
|
-
# --------------Boundary-00=_00000000000000000000
|
54
|
-
# Content-Type: message/delivery-status; name="deliverystatus.txt"
|
55
|
-
#
|
56
|
-
v = dscontents[-1]
|
57
|
-
|
58
|
-
if Sisimai::String.aligned(e, ['<', '@', '>', '(', ')'])
|
59
|
-
# <kijitora@example.co.jp> (Unknown user kijitora@example.co.jp)
|
60
|
-
if v['recipient']
|
61
|
-
# There are multiple recipient addresses in the message body.
|
62
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
63
|
-
v = dscontents[-1]
|
64
|
-
end
|
65
|
-
v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.index('>')])
|
66
|
-
issuedcode = e[e.index('(') + 1, e.size]
|
67
|
-
recipients += 1
|
68
|
-
|
69
|
-
elsif f = Sisimai::RFC1894.match(e)
|
70
|
-
# "e" matched with any field defined in RFC3464
|
71
|
-
o = Sisimai::RFC1894.field(e)
|
72
|
-
unless o
|
73
|
-
# Fallback code for empty value or invalid formatted value
|
74
|
-
# - Original-Recipient: <kijitora@example.co.jp>
|
75
|
-
if e.start_with?('Original-Recipient: ')
|
76
|
-
v['alias'] = Sisimai::Address.s3s4(e[e.index(':') + 1, e.size])
|
77
|
-
end
|
78
|
-
next
|
79
|
-
end
|
80
|
-
next unless fieldtable[o[0]]
|
81
|
-
v[fieldtable[o[0]]] = o[2]
|
82
|
-
|
83
|
-
else
|
84
|
-
# Continued line of the value of Diagnostic-Code field
|
85
|
-
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
86
|
-
next unless e.start_with?(' ')
|
87
|
-
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
88
|
-
readslices[-1] = 'Diagnostic-Code: ' << e
|
89
|
-
end
|
90
|
-
end
|
91
|
-
return nil unless recipients > 0
|
92
|
-
|
93
|
-
dscontents.each do |e|
|
94
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode)
|
95
|
-
MessagesOf.each_key do |r|
|
96
|
-
# Verify each regular expression of session errors
|
97
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
98
|
-
e['reason'] = r
|
99
|
-
break
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
104
|
-
end
|
105
|
-
def description; return 'McAfee Email Appliance'; end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
@@ -1,120 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MessageLabs decodes a bounce email which created by Email Security (formerly MessageLab)
|
3
|
-
# https://www.broadcom.com/products/cybersecurity/emails.
|
4
|
-
# Methods in the module are called from only Sisimai::Message.
|
5
|
-
module MessageLabs
|
6
|
-
class << self
|
7
|
-
require 'sisimai/lhost'
|
8
|
-
|
9
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
11
|
-
StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
|
12
|
-
MessagesOf = {
|
13
|
-
'userunknown' => ['542 ', ' Rejected', 'No such user'],
|
14
|
-
'securityerror' => ['Please turn on SMTP Authentication in your mail client'],
|
15
|
-
}.freeze
|
16
|
-
|
17
|
-
# @abstract Decodes the bounce message from Email Security (formerly Symantec.cloud (formerly MessageLabs))
|
18
|
-
# @param [Hash] mhead Message headers of a bounce email
|
19
|
-
# @param [String] mbody Message body of a bounce email
|
20
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
21
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
22
|
-
def inquire(mhead, mbody)
|
23
|
-
# X-Msg-Ref: server-11.tower-143.messagelabs.com!1419367175!36473369!1
|
24
|
-
# X-Originating-IP: [10.245.230.38]
|
25
|
-
# X-StarScan-Received:
|
26
|
-
# X-StarScan-Version: 6.12.5; banners=-,-,-
|
27
|
-
# X-VirusChecked: Checked
|
28
|
-
return nil unless mhead['x-msg-ref']
|
29
|
-
return nil unless mhead['from'].include?('MAILER-DAEMON@messagelabs.com')
|
30
|
-
return nil unless mhead['subject'].start_with?('Mail Delivery Failure')
|
31
|
-
|
32
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
33
|
-
permessage = {} # (Hash) Store values of each Per-Message field
|
34
|
-
|
35
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
36
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
37
|
-
bodyslices = emailparts[0].split("\n")
|
38
|
-
readslices = ['']
|
39
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
40
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
41
|
-
commandset = [] # (Array) ``in reply to * command'' list
|
42
|
-
v = nil
|
43
|
-
|
44
|
-
while e = bodyslices.shift do
|
45
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
46
|
-
# line of the beginning of the original message.
|
47
|
-
readslices << e # Save the current line for the next loop
|
48
|
-
|
49
|
-
if readcursor == 0
|
50
|
-
# Beginning of the bounce message or message/delivery-status part
|
51
|
-
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
52
|
-
next
|
53
|
-
end
|
54
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
55
|
-
next if e.empty?
|
56
|
-
|
57
|
-
if f = Sisimai::RFC1894.match(e)
|
58
|
-
# "e" matched with any field defined in RFC3464
|
59
|
-
next unless o = Sisimai::RFC1894.field(e)
|
60
|
-
v = dscontents[-1]
|
61
|
-
|
62
|
-
if o[-1] == 'addr'
|
63
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
64
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
65
|
-
if o[0] == 'final-recipient'
|
66
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
67
|
-
if v['recipient']
|
68
|
-
# There are multiple recipient addresses in the message body.
|
69
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
70
|
-
v = dscontents[-1]
|
71
|
-
end
|
72
|
-
v['recipient'] = o[2]
|
73
|
-
recipients += 1
|
74
|
-
else
|
75
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
76
|
-
v['alias'] = o[2]
|
77
|
-
end
|
78
|
-
elsif o[-1] == 'code'
|
79
|
-
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
80
|
-
v['spec'] = o[1]
|
81
|
-
v['diagnosis'] = o[2]
|
82
|
-
else
|
83
|
-
# Other DSN fields defined in RFC3464
|
84
|
-
next unless fieldtable[o[0]]
|
85
|
-
v[fieldtable[o[0]]] = o[2]
|
86
|
-
|
87
|
-
next unless f
|
88
|
-
permessage[fieldtable[o[0]]] = o[2]
|
89
|
-
end
|
90
|
-
else
|
91
|
-
# Continued line of the value of Diagnostic-Code field
|
92
|
-
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
93
|
-
next unless e.start_with?(' ')
|
94
|
-
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
95
|
-
readslices[-1] = 'Diagnostic-Code: ' << e
|
96
|
-
end
|
97
|
-
end
|
98
|
-
return nil unless recipients > 0
|
99
|
-
|
100
|
-
dscontents.each do |e|
|
101
|
-
# Set default values if each value is empty.
|
102
|
-
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
103
|
-
e['command'] = commandset.shift || ''
|
104
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
105
|
-
|
106
|
-
MessagesOf.each_key do |r|
|
107
|
-
# Verify each regular expression of session errors
|
108
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
109
|
-
e['reason'] = r
|
110
|
-
break
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
115
|
-
end
|
116
|
-
def description; return 'Symantec.cloud http://www.messagelabs.com'; end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|