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
@@ -1,118 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::PowerMTA decodes a bounce email which created by PowerMTA https://bird.com/email/power-mta.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module PowerMTA
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
10
|
-
StartingOf = { message: ['Hello, this is the mail server on '] }.freeze
|
11
|
-
Categories = {
|
12
|
-
'bad-domain' => 'hostunknown',
|
13
|
-
'bad-mailbox' => 'userunknown',
|
14
|
-
'inactive-mailbox' => 'disabled',
|
15
|
-
'message-expired' => 'expired',
|
16
|
-
'no-answer-from-host' => 'networkerror',
|
17
|
-
'policy-related' => 'policyviolation',
|
18
|
-
'quota-issues' => 'mailboxfull',
|
19
|
-
'routing-errors' => 'systemerror',
|
20
|
-
'spam-related' => 'spamdetected',
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
# @abstract Decodes the bounce message from PowerMTA
|
24
|
-
# @param [Hash] mhead Message headers of a bounce email
|
25
|
-
# @param [String] mbody Message body of a bounce email
|
26
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
27
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
28
|
-
# @since v4.25.6
|
29
|
-
def inquire(mhead, mbody)
|
30
|
-
return nil unless mhead['subject'].to_s.start_with?('Delivery report')
|
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
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
39
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
40
|
-
v = nil
|
41
|
-
|
42
|
-
while e = bodyslices.shift do
|
43
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
44
|
-
# line of the beginning of the original message.
|
45
|
-
if readcursor == 0
|
46
|
-
# Beginning of the bounce message or message/delivery-status part
|
47
|
-
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
48
|
-
next
|
49
|
-
end
|
50
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
51
|
-
next if e.empty?
|
52
|
-
|
53
|
-
if f = Sisimai::RFC1894.match(e)
|
54
|
-
# "e" matched with any field defined in RFC3464
|
55
|
-
next unless o = Sisimai::RFC1894.field(e)
|
56
|
-
v = dscontents[-1]
|
57
|
-
|
58
|
-
if o[-1] == 'addr'
|
59
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
60
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
61
|
-
if o[0] == 'final-recipient'
|
62
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
63
|
-
if v['recipient']
|
64
|
-
# There are multiple recipient addresses in the message body.
|
65
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
66
|
-
v = dscontents[-1]
|
67
|
-
end
|
68
|
-
v['recipient'] = o[2]
|
69
|
-
recipients += 1
|
70
|
-
else
|
71
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
72
|
-
v['alias'] = o[2]
|
73
|
-
end
|
74
|
-
elsif o[-1] == 'code'
|
75
|
-
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
76
|
-
v['spec'] = o[1]
|
77
|
-
v['diagnosis'] = o[2]
|
78
|
-
else
|
79
|
-
# Other DSN fields defined in RFC3464
|
80
|
-
next unless fieldtable[o[0]]
|
81
|
-
v[fieldtable[o[0]]] = o[2]
|
82
|
-
|
83
|
-
next unless f
|
84
|
-
permessage[fieldtable[o[0]]] = o[2]
|
85
|
-
end
|
86
|
-
else
|
87
|
-
# Hello, this is the mail server on neko2.example.org.
|
88
|
-
#
|
89
|
-
# I am sending you this message to inform you on the delivery status of a
|
90
|
-
# message you previously sent. Immediately below you will find a list of
|
91
|
-
# the affected recipients; also attached is a Delivery Status Notification
|
92
|
-
# (DSN) report in standard format, as well as the headers of the original
|
93
|
-
# message.
|
94
|
-
#
|
95
|
-
# <kijitora@example.jp> delivery failed; will not continue trying
|
96
|
-
#
|
97
|
-
if e.start_with?('X-PowerMTA-BounceCategory: ')
|
98
|
-
# X-PowerMTA-BounceCategory: bad-mailbox
|
99
|
-
v['category'] = e[e.index(':') + 2, e.size]
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
return nil unless recipients > 0
|
104
|
-
|
105
|
-
dscontents.each do |e|
|
106
|
-
# Set default values if each value is empty.
|
107
|
-
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
108
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].to_s.tr("\n", ' '))
|
109
|
-
e['reason'] = Categories[e['category']] || ''
|
110
|
-
end
|
111
|
-
|
112
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
113
|
-
end
|
114
|
-
def description; return 'PowerMTA: https://www.sparkpost.com/powermta/'; end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
@@ -1,126 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::ReceivingSES decodes a bounce email which created by Amazon Simple Email Service
|
3
|
-
# https://aws.amazon.com/ses. Methods in the module are called from only Sisimai::Message.
|
4
|
-
module ReceivingSES
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
# https://aws.amazon.com/ses/
|
9
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
11
|
-
StartingOf = { message: ['This message could not be delivered.'] }.freeze
|
12
|
-
MessagesOf = {
|
13
|
-
# The followings are error messages in Rule sets/*/Actions/Template
|
14
|
-
'filtered' => ['Mailbox does not exist'],
|
15
|
-
'mesgtoobig' => ['Message too large'],
|
16
|
-
'mailboxfull' => ['Mailbox full'],
|
17
|
-
'contenterror' => ['Message content rejected'],
|
18
|
-
}.freeze
|
19
|
-
|
20
|
-
# @abstract Decodes the bounce message from Amazon SES/Receiving
|
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
|
-
# X-SES-Outgoing: 2015.10.01-54.240.27.7
|
27
|
-
# Feedback-ID: 1.us-west-2.HX6/J9OVlHTadQhEu1+wdF9DBj6n6Pa9sW5Y/0pSOi8=:AmazonSES
|
28
|
-
return nil unless mhead['x-ses-outgoing']
|
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
|
-
readslices = ['']
|
37
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
38
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
39
|
-
v = nil
|
40
|
-
|
41
|
-
while e = bodyslices.shift do
|
42
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
43
|
-
# line of the beginning of the original message.
|
44
|
-
readslices << e # Save the current line for the next loop
|
45
|
-
|
46
|
-
if readcursor == 0
|
47
|
-
# Beginning of the bounce message or message/delivery-status part
|
48
|
-
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
49
|
-
next
|
50
|
-
end
|
51
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
52
|
-
next if e.empty?
|
53
|
-
|
54
|
-
if f = Sisimai::RFC1894.match(e)
|
55
|
-
# "e" matched with any field defined in RFC3464
|
56
|
-
next unless o = Sisimai::RFC1894.field(e)
|
57
|
-
v = dscontents[-1]
|
58
|
-
|
59
|
-
if o[-1] == 'addr'
|
60
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
61
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
62
|
-
if o[0] == 'final-recipient'
|
63
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
64
|
-
if v['recipient']
|
65
|
-
# There are multiple recipient addresses in the message body.
|
66
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
67
|
-
v = dscontents[-1]
|
68
|
-
end
|
69
|
-
v['recipient'] = o[2]
|
70
|
-
recipients += 1
|
71
|
-
else
|
72
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
73
|
-
v['alias'] = o[2]
|
74
|
-
end
|
75
|
-
elsif o[-1] == 'code'
|
76
|
-
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
77
|
-
v['spec'] = o[1]
|
78
|
-
v['diagnosis'] = o[2]
|
79
|
-
else
|
80
|
-
# Other DSN fields defined in RFC3464
|
81
|
-
next unless fieldtable[o[0]]
|
82
|
-
v[fieldtable[o[0]]] = o[2]
|
83
|
-
|
84
|
-
next unless f
|
85
|
-
permessage[fieldtable[o[0]]] = o[2]
|
86
|
-
end
|
87
|
-
else
|
88
|
-
# Continued line of the value of Diagnostic-Code field
|
89
|
-
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
90
|
-
next unless e.start_with?(' ')
|
91
|
-
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
92
|
-
readslices[-1] = 'Diagnostic-Code: ' << e
|
93
|
-
end
|
94
|
-
end
|
95
|
-
return nil unless recipients > 0
|
96
|
-
|
97
|
-
dscontents.each do |e|
|
98
|
-
# Set default values if each value is empty.
|
99
|
-
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
100
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].tr("\n", ' '))
|
101
|
-
|
102
|
-
if e['status'].to_s.start_with?('5.0.0', '5.1.0', '4.0.0', '4.1.0')
|
103
|
-
# Get other D.S.N. value from the error message
|
104
|
-
errormessage = e['diagnosis']
|
105
|
-
p1 = e['diagnosis'].index("-'"); p1 = e['diagnosis'].index('-"') unless p1
|
106
|
-
p2 = e['diagnosis'].rindex("' "); p2 = e['diagnosis'].rindex('" ') unless p2
|
107
|
-
errormessage = e['diagnosis'][p1 + 2, p2 - p1 - 2] if p1 && p2
|
108
|
-
e['status'] = Sisimai::SMTP::Status.find(errormessage) || e['status']
|
109
|
-
end
|
110
|
-
|
111
|
-
MessagesOf.each_key do |r|
|
112
|
-
# Verify each regular expression of session errors
|
113
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
114
|
-
e['reason'] = r
|
115
|
-
break
|
116
|
-
end
|
117
|
-
e['reason'] ||= Sisimai::SMTP::Status.name(e['status']) || ''
|
118
|
-
end
|
119
|
-
|
120
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
121
|
-
end
|
122
|
-
def description; return 'Amazon SES(Receiving): https://aws.amazon.com/ses/'; end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
@@ -1,150 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::SendGrid decodes a bounce email which created by Twilio SendGrid https://sendgrid.com/.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module SendGrid
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: message/rfc822'].freeze
|
10
|
-
StartingOf = { message: ['This is an automatically generated message from SendGrid.'] }.freeze
|
11
|
-
|
12
|
-
# @abstract Decodes the bounce message from Twilio SendGrid
|
13
|
-
# @param [Hash] mhead Message headers of a bounce email
|
14
|
-
# @param [String] mbody Message body of a bounce email
|
15
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
16
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
17
|
-
def inquire(mhead, mbody)
|
18
|
-
# Return-Path: <apps@sendgrid.net>
|
19
|
-
# X-Mailer: MIME-tools 5.502 (Entity 5.502)
|
20
|
-
return nil unless mhead['return-path']
|
21
|
-
return nil unless mhead['return-path'] == '<apps@sendgrid.net>'
|
22
|
-
return nil unless mhead['subject'] == 'Undelivered Mail Returned to Sender'
|
23
|
-
|
24
|
-
require 'sisimai/smtp/command'
|
25
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
26
|
-
permessage = {} # (Hash) Store values of each Per-Message field
|
27
|
-
|
28
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
29
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
30
|
-
bodyslices = emailparts[0].split("\n")
|
31
|
-
readslices = ['']
|
32
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
33
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
34
|
-
thecommand = '' # (String) SMTP Command name begin with the string '>>>'
|
35
|
-
v = nil
|
36
|
-
|
37
|
-
while e = bodyslices.shift do
|
38
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
39
|
-
# line of the beginning of the original message.
|
40
|
-
readslices << e # Save the current line for the next loop
|
41
|
-
|
42
|
-
if readcursor == 0
|
43
|
-
# Beginning of the bounce message or message/delivery-status part
|
44
|
-
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
45
|
-
next
|
46
|
-
end
|
47
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
48
|
-
next if e.empty?
|
49
|
-
|
50
|
-
if f = Sisimai::RFC1894.match(e)
|
51
|
-
# "e" matched with any field defined in RFC3464
|
52
|
-
o = Sisimai::RFC1894.field(e)
|
53
|
-
v = dscontents[-1]
|
54
|
-
|
55
|
-
unless o
|
56
|
-
# Fallback code for empty value or invalid formatted value
|
57
|
-
# - Status: (empty)
|
58
|
-
# - Diagnostic-Code: 550 5.1.1 ... (No "diagnostic-type" sub field)
|
59
|
-
v['diagnosis'] = e[e.index(':') + 2, e.size] if e.start_with?('Diagnostic-Code: ')
|
60
|
-
next
|
61
|
-
end
|
62
|
-
|
63
|
-
if o[-1] == 'addr'
|
64
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
65
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
66
|
-
if o[0] == 'final-recipient'
|
67
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
68
|
-
if v['recipient']
|
69
|
-
# There are multiple recipient addresses in the message body.
|
70
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
71
|
-
v = dscontents[-1]
|
72
|
-
end
|
73
|
-
v['recipient'] = o[2]
|
74
|
-
recipients += 1
|
75
|
-
else
|
76
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
77
|
-
v['alias'] = o[2]
|
78
|
-
end
|
79
|
-
elsif o[-1] == 'code'
|
80
|
-
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
81
|
-
v['spec'] = o[1]
|
82
|
-
v['diagnosis'] = o[2]
|
83
|
-
elsif o[-1] == 'date'
|
84
|
-
# Arrival-Date: 2012-12-31 23-59-59
|
85
|
-
next unless e.start_with?('Arrival-Date: ')
|
86
|
-
cf = e[e.index(': ') + 2, e.size].split(' '); next unless cf.size == 2
|
87
|
-
cw = cf[0].split('-'); next unless cw.size == 3
|
88
|
-
ce = cf[1].split('-'); next unless ce.size == 3
|
89
|
-
|
90
|
-
o[1] << 'Thu, ' << cw[2] + ' '
|
91
|
-
o[1] << Sisimai::DateTime.monthname(false)[cw[1].to_i - 1]
|
92
|
-
o[1] << ' ' << cw[0] + ' ' << ce.join(':')
|
93
|
-
o[1] << ' ' << Sisimai::DateTime.abbr2tz('CDT')
|
94
|
-
else
|
95
|
-
# Other DSN fields defined in RFC3464
|
96
|
-
next unless fieldtable[o[0]]
|
97
|
-
v[fieldtable[o[0]]] = o[2]
|
98
|
-
|
99
|
-
next unless f
|
100
|
-
permessage[fieldtable[o[0]]] = o[2]
|
101
|
-
end
|
102
|
-
else
|
103
|
-
# The line does not begin with a DSN field defined in RFC3464
|
104
|
-
if cv = Sisimai::SMTP::Command.find(e)
|
105
|
-
# in RCPT TO, in MAIL FROM, end of DATA
|
106
|
-
thecommand = cv
|
107
|
-
elsif e.start_with?('Diagnostic-Code: ')
|
108
|
-
# Diagnostic-Code: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
109
|
-
v['diagnosis'] = e[e.index(':') + 2, e.size]
|
110
|
-
else
|
111
|
-
# Continued line of the value of Diagnostic-Code field
|
112
|
-
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
113
|
-
next unless e.start_with?(' ')
|
114
|
-
v['diagnosis'] ||= ''
|
115
|
-
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
116
|
-
readslices[-1] = 'Diagnostic-Code: ' << e
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
return nil unless recipients > 0
|
121
|
-
|
122
|
-
dscontents.each do |e|
|
123
|
-
# Get the value of SMTP status code as a pseudo D.S.N.
|
124
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
125
|
-
e['replycode'] = Sisimai::SMTP::Reply.find(e['diagnosis']) || ''
|
126
|
-
e['status'] = e['replycode'][0, 1] + '.0.0' if e['replycode'].size == 3
|
127
|
-
e['command'] = thecommand
|
128
|
-
|
129
|
-
if e['status'] == '5.0.0' || e['status'] == '4.0.0'
|
130
|
-
# Get the value of D.S.N. from the error message or the value of Diagnostic-Code header.
|
131
|
-
e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || e['status']
|
132
|
-
end
|
133
|
-
|
134
|
-
if e['action'] == 'expired'
|
135
|
-
# Action: expired
|
136
|
-
e['reason'] = 'expired'
|
137
|
-
if !e['status'] || e['status'].end_with?('.0.0')
|
138
|
-
# Set pseudo Status code value if the value of Status is not defined or 4.0.0 or 5.0.0.
|
139
|
-
e['status'] = Sisimai::SMTP::Status.code('expired') || e['status']
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
145
|
-
end
|
146
|
-
def description; return 'SendGrid: https://sendgrid.com/'; end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
@@ -1,105 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::SurfControl decodes a bounce email which created by WebSense SurfControl.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module SurfControl
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: message/rfc822'].freeze
|
10
|
-
StartingOf = { message: ['Your message could not be sent.'] }.freeze
|
11
|
-
|
12
|
-
# @abstract Decodes the bounce message from SurfControl
|
13
|
-
# @param [Hash] mhead Message headers of a bounce email
|
14
|
-
# @param [String] mbody Message body of a bounce email
|
15
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
16
|
-
# @return [Nil] it failed to decode or the arguments are missing
|
17
|
-
def inquire(mhead, mbody)
|
18
|
-
# X-SEF-ZeroHour-RefID: fgs=000000000
|
19
|
-
# X-SEF-Processed: 0_0_0_000__2010_04_29_23_34_45
|
20
|
-
# X-Mailer: SurfControl E-mail Filter
|
21
|
-
return nil unless mhead['x-sef-processed']
|
22
|
-
return nil unless mhead['x-mailer']
|
23
|
-
return nil unless mhead['x-mailer'] == 'SurfControl E-mail Filter'
|
24
|
-
|
25
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
26
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
27
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
28
|
-
bodyslices = emailparts[0].split("\n")
|
29
|
-
readslices = ['']
|
30
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
31
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
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 == StartingOf[:message][0]
|
42
|
-
next
|
43
|
-
end
|
44
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
45
|
-
next if e.empty?
|
46
|
-
|
47
|
-
# Your message could not be sent.
|
48
|
-
# A transcript of the attempts to send the message follows.
|
49
|
-
# The number of attempts made: 1
|
50
|
-
# Addressed To: kijitora@example.com
|
51
|
-
#
|
52
|
-
# Thu 29 Apr 2010 23:34:45 +0900
|
53
|
-
# Failed to send to identified host,
|
54
|
-
# kijitora@example.com: [192.0.2.5], 550 kijitora@example.com... No such user
|
55
|
-
# --- Message non-deliverable.
|
56
|
-
v = dscontents[-1]
|
57
|
-
|
58
|
-
if e.start_with?('Addressed To:') && e.index('@') > 1
|
59
|
-
# Addressed To: kijitora@example.com
|
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(':') + 2, e.size])
|
66
|
-
recipients += 1
|
67
|
-
|
68
|
-
elsif %w[Sun Mon Tue Wed Thu Fri Sat].any? { |a| e.start_with?(a) }
|
69
|
-
# Thu 29 Apr 2010 23:34:45 +0900
|
70
|
-
v['date'] = e
|
71
|
-
|
72
|
-
elsif Sisimai::String.aligned(e, ['@', ':', ' ', '[', '],', '...'])
|
73
|
-
# kijitora@example.com: [192.0.2.5], 550 kijitora@example.com... No such user
|
74
|
-
p1 = e.index('[')
|
75
|
-
p2 = e.index('],', p1 + 1)
|
76
|
-
v['rhost'] = e[p1 + 1, p2 - p1 - 1]
|
77
|
-
v['diagnosis'] = Sisimai::String.sweep(e[p2 + 2, e.size])
|
78
|
-
|
79
|
-
else
|
80
|
-
# Fallback, Decode RFC3464 headers.
|
81
|
-
if f = Sisimai::RFC1894.match(e)
|
82
|
-
# "e" matched with any field defined in RFC3464
|
83
|
-
next unless o = Sisimai::RFC1894.field(e)
|
84
|
-
next if o[1] == 'final-recipient'
|
85
|
-
next unless fieldtable[o[0]]
|
86
|
-
v[fieldtable[o[0]]] = o[2]
|
87
|
-
else
|
88
|
-
# Continued line of the value of Diagnostic-Code field
|
89
|
-
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
90
|
-
next unless e.start_with?(' ')
|
91
|
-
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
92
|
-
readslices[-1] = 'Diagnostic-Code: ' << e
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
return nil unless recipients > 0
|
97
|
-
|
98
|
-
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
99
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
100
|
-
end
|
101
|
-
def description; return 'WebSense SurfControl'; end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|