sisimai 5.0.3-java → 5.2.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/codecovio.yml +3 -1
- data/.github/workflows/rake-test.yml +7 -3
- data/ChangeLog.md +136 -0
- data/Makefile +4 -2
- data/README-JA.md +32 -22
- data/README.md +31 -21
- data/lib/sisimai/arf.rb +124 -213
- data/lib/sisimai/fact/json.rb +2 -2
- data/lib/sisimai/fact/yaml.rb +2 -2
- data/lib/sisimai/fact.rb +208 -173
- data/lib/sisimai/lda.rb +98 -0
- data/lib/sisimai/lhost/activehunter.rb +5 -4
- data/lib/sisimai/lhost/amazonses.rb +189 -305
- data/lib/sisimai/lhost/apachejames.rb +52 -55
- data/lib/sisimai/lhost/biglobe.rb +5 -6
- data/lib/sisimai/lhost/courier.rb +14 -12
- data/lib/sisimai/lhost/domino.rb +29 -29
- data/lib/sisimai/lhost/dragonfly.rb +113 -0
- data/lib/sisimai/lhost/einsundeins.rb +7 -8
- data/lib/sisimai/lhost/exchange2003.rb +10 -11
- data/lib/sisimai/lhost/exchange2007.rb +115 -104
- data/lib/sisimai/lhost/exim.rb +236 -246
- data/lib/sisimai/lhost/ezweb.rb +47 -55
- data/lib/sisimai/lhost/fml.rb +6 -7
- data/lib/sisimai/lhost/gmail.rb +36 -32
- data/lib/sisimai/lhost/gmx.rb +8 -20
- data/lib/sisimai/lhost/googlegroups.rb +13 -12
- data/lib/sisimai/lhost/googleworkspace.rb +94 -0
- data/lib/sisimai/lhost/imailserver.rb +11 -19
- data/lib/sisimai/lhost/interscanmss.rb +6 -5
- data/lib/sisimai/lhost/kddi.rb +7 -8
- data/lib/sisimai/lhost/mailfoundry.rb +6 -9
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +6 -6
- data/lib/sisimai/lhost/messagingserver.rb +19 -17
- data/lib/sisimai/lhost/mfilter.rb +8 -7
- data/lib/sisimai/lhost/notes.rb +6 -8
- data/lib/sisimai/lhost/opensmtpd.rb +11 -9
- data/lib/sisimai/lhost/postfix.rb +29 -31
- data/lib/sisimai/lhost/qmail.rb +136 -112
- data/lib/sisimai/lhost/sendmail.rb +23 -22
- data/lib/sisimai/lhost/v5sendmail.rb +93 -64
- data/lib/sisimai/lhost/verizon.rb +6 -6
- data/lib/sisimai/lhost/x1.rb +4 -4
- data/lib/sisimai/lhost/x2.rb +4 -5
- data/lib/sisimai/lhost/x3.rb +5 -5
- data/lib/sisimai/lhost/x6.rb +4 -4
- data/lib/sisimai/lhost/zoho.rb +6 -6
- data/lib/sisimai/lhost.rb +21 -24
- data/lib/sisimai/mail/maildir.rb +1 -1
- data/lib/sisimai/mail/stdin.rb +1 -1
- data/lib/sisimai/message.rb +100 -153
- data/lib/sisimai/order.rb +22 -77
- data/lib/sisimai/reason/authfailure.rb +1 -4
- data/lib/sisimai/reason/badreputation.rb +3 -3
- 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 +3 -3
- data/lib/sisimai/reason/notaccept.rb +2 -3
- data/lib/sisimai/reason/notcompliantrfc.rb +10 -4
- data/lib/sisimai/reason/rejected.rb +2 -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 +82 -78
- 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 +224 -345
- data/lib/sisimai/rfc3834.rb +3 -3
- 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 +95 -0
- data/lib/sisimai/rhost/cox.rb +84 -34
- data/lib/sisimai/rhost/facebook.rb +100 -0
- data/lib/sisimai/rhost/franceptt.rb +87 -83
- data/lib/sisimai/rhost/godaddy.rb +208 -45
- data/lib/sisimai/rhost/google.rb +22 -22
- data/lib/sisimai/rhost/gsuite.rb +42 -0
- data/lib/sisimai/rhost/iua.rb +5 -5
- data/lib/sisimai/rhost/kddi.rb +9 -7
- data/lib/sisimai/rhost/messagelabs.rb +37 -0
- data/lib/sisimai/rhost/microsoft.rb +60 -54
- data/lib/sisimai/rhost/mimecast.rb +44 -31
- data/lib/sisimai/rhost/nttdocomo.rb +5 -4
- data/lib/sisimai/rhost/outlook.rb +36 -0
- data/lib/sisimai/rhost/spectrum.rb +102 -41
- data/lib/sisimai/rhost/tencent.rb +48 -26
- data/lib/sisimai/rhost/yahooinc.rb +111 -0
- data/lib/sisimai/rhost.rb +65 -42
- data/lib/sisimai/smtp/command.rb +31 -21
- data/lib/sisimai/smtp/failure.rb +103 -0
- data/lib/sisimai/smtp/reply.rb +29 -24
- data/lib/sisimai/smtp/status.rb +36 -19
- data/lib/sisimai/smtp/transcript.rb +18 -18
- data/lib/sisimai/string.rb +0 -46
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +0 -6
- data/set-of-emails/maildir/bsd/lhost-dragonfly-01.eml +36 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-02.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-03.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-04.eml +31 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-05.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-06.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-07.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-08.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-09.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-10.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-11.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-12.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-13.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-14.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-15.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-16.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-17.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-18.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-19.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-20.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-21.eml +33 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-22.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-23.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-24.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-25.eml +33 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-26.eml +33 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-27.eml +47 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-28.eml +47 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-29.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-dragonfly-30.eml +32 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-10.eml +58 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-11.eml +58 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-12.eml +62 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-13.eml +62 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-14.eml +58 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-15.eml +63 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-16.eml +62 -0
- data/set-of-emails/maildir/bsd/lhost-opensmtpd-17.eml +63 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-30.eml +81 -81
- data/set-of-emails/maildir/bsd/lhost-qmail-11.eml +29 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-12.eml +29 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-13.eml +29 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-14.eml +34 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-15.eml +30 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-16.eml +31 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-17.eml +38 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-18.eml +31 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-19.eml +31 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-20.eml +46 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-21.eml +41 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-22.eml +42 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-23.eml +43 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-24.eml +43 -0
- data/set-of-emails/maildir/bsd/lhost-qmail-25.eml +54 -0
- 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-apple-01.eml +79 -0
- data/set-of-emails/maildir/bsd/rhost-apple-02.eml +81 -0
- data/set-of-emails/maildir/bsd/rhost-apple-03.eml +75 -0
- data/set-of-emails/maildir/bsd/rhost-apple-04.eml +74 -0
- 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/bsd/rhost-yahooinc-01.eml +80 -0
- data/set-of-emails/maildir/bsd/rhost-yahooinc-02.eml +83 -0
- data/set-of-emails/maildir/bsd/rhost-yahooinc-03.eml +125 -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 +136 -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 -119
- 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/mcafee.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::McAfee parses a bounce email which created by McAfee Email Appliance. Methods in
|
3
|
-
# 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
|
-
# Parse bounce messages 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 parse 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,119 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MessageLabs parses a bounce email which created by Symantec.cloud: formerly MessageLabs.
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module MessageLabs
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: text/rfc822-headers'].freeze
|
10
|
-
StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
|
11
|
-
MessagesOf = {
|
12
|
-
'userunknown' => ['542 ', ' Rejected', 'No such user'],
|
13
|
-
'securityerror' => ['Please turn on SMTP Authentication in your mail client'],
|
14
|
-
}.freeze
|
15
|
-
|
16
|
-
# Parse bounce messages from Symantec.cloud(MessageLabs)
|
17
|
-
# @param [Hash] mhead Message headers of a bounce email
|
18
|
-
# @param [String] mbody Message body of a bounce email
|
19
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
20
|
-
# @return [Nil] it failed to parse or the arguments are missing
|
21
|
-
def inquire(mhead, mbody)
|
22
|
-
# X-Msg-Ref: server-11.tower-143.messagelabs.com!1419367175!36473369!1
|
23
|
-
# X-Originating-IP: [10.245.230.38]
|
24
|
-
# X-StarScan-Received:
|
25
|
-
# X-StarScan-Version: 6.12.5; banners=-,-,-
|
26
|
-
# X-VirusChecked: Checked
|
27
|
-
return nil unless mhead['x-msg-ref']
|
28
|
-
return nil unless mhead['from'].include?('MAILER-DAEMON@messagelabs.com')
|
29
|
-
return nil unless mhead['subject'].start_with?('Mail Delivery Failure')
|
30
|
-
|
31
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
32
|
-
permessage = {} # (Hash) Store values of each Per-Message field
|
33
|
-
|
34
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
35
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
36
|
-
bodyslices = emailparts[0].split("\n")
|
37
|
-
readslices = ['']
|
38
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
39
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
40
|
-
commandset = [] # (Array) ``in reply to * command'' list
|
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
|
-
readslices << e # Save the current line for the next loop
|
47
|
-
|
48
|
-
if readcursor == 0
|
49
|
-
# Beginning of the bounce message or message/delivery-status part
|
50
|
-
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
51
|
-
next
|
52
|
-
end
|
53
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
54
|
-
next if e.empty?
|
55
|
-
|
56
|
-
if f = Sisimai::RFC1894.match(e)
|
57
|
-
# "e" matched with any field defined in RFC3464
|
58
|
-
next unless o = Sisimai::RFC1894.field(e)
|
59
|
-
v = dscontents[-1]
|
60
|
-
|
61
|
-
if o[-1] == 'addr'
|
62
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
63
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
64
|
-
if o[0] == 'final-recipient'
|
65
|
-
# Final-Recipient: rfc822; kijitora@example.jp
|
66
|
-
if v['recipient']
|
67
|
-
# There are multiple recipient addresses in the message body.
|
68
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
69
|
-
v = dscontents[-1]
|
70
|
-
end
|
71
|
-
v['recipient'] = o[2]
|
72
|
-
recipients += 1
|
73
|
-
else
|
74
|
-
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
75
|
-
v['alias'] = o[2]
|
76
|
-
end
|
77
|
-
elsif o[-1] == 'code'
|
78
|
-
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
79
|
-
v['spec'] = o[1]
|
80
|
-
v['diagnosis'] = o[2]
|
81
|
-
else
|
82
|
-
# Other DSN fields defined in RFC3464
|
83
|
-
next unless fieldtable[o[0]]
|
84
|
-
v[fieldtable[o[0]]] = o[2]
|
85
|
-
|
86
|
-
next unless f
|
87
|
-
permessage[fieldtable[o[0]]] = o[2]
|
88
|
-
end
|
89
|
-
else
|
90
|
-
# Continued line of the value of Diagnostic-Code field
|
91
|
-
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
92
|
-
next unless e.start_with?(' ')
|
93
|
-
v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
|
94
|
-
readslices[-1] = 'Diagnostic-Code: ' << e
|
95
|
-
end
|
96
|
-
end
|
97
|
-
return nil unless recipients > 0
|
98
|
-
|
99
|
-
dscontents.each do |e|
|
100
|
-
# Set default values if each value is empty.
|
101
|
-
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
102
|
-
e['command'] = commandset.shift || ''
|
103
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
104
|
-
|
105
|
-
MessagesOf.each_key do |r|
|
106
|
-
# Verify each regular expression of session errors
|
107
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
108
|
-
e['reason'] = r
|
109
|
-
break
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
114
|
-
end
|
115
|
-
def description; return 'Symantec.cloud http://www.messagelabs.com'; end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
@@ -1,198 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::MXLogic parses a bounce email which created by McAfee SaaS (formerly MX Logic).
|
3
|
-
# Methods in the module are called from only Sisimai::Message.
|
4
|
-
module MXLogic
|
5
|
-
class << self
|
6
|
-
# Based on Sisimai::Lhost::Exim
|
7
|
-
require 'sisimai/lhost'
|
8
|
-
|
9
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
Boundaries = ['Included is a copy of the message header:'].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
|
-
# % find exim/ -type f -exec grep 'message = US' {} /dev/null \;
|
18
|
-
# route.c:1158| DEBUG(D_uid) debug_printf("getpwnam() returned NULL (user not found)\n");
|
19
|
-
'userunknown' => ['user not found'],
|
20
|
-
# transports/smtp.c:3524| addr->message = US"all host address lookups failed permanently";
|
21
|
-
# routers/dnslookup.c:331| addr->message = US"all relevant MX records point to non-existent hosts";
|
22
|
-
# route.c:1826| uschar *message = US"Unrouteable address";
|
23
|
-
'hostunknown' => [
|
24
|
-
'all host address lookups failed permanently',
|
25
|
-
'all relevant MX records point to non-existent hosts',
|
26
|
-
'Unrouteable address',
|
27
|
-
],
|
28
|
-
# transports/appendfile.c:2567| addr->user_message = US"mailbox is full";
|
29
|
-
# transports/appendfile.c:3049| addr->message = string_sprintf("mailbox is full "
|
30
|
-
# transports/appendfile.c:3050| "(quota exceeded while writing to file %s)", filename);
|
31
|
-
'mailboxfull' => ['mailbox is full', 'error: quota exceed'],
|
32
|
-
# routers/dnslookup.c:328| addr->message = US"an MX or SRV record indicated no SMTP service";
|
33
|
-
# transports/smtp.c:3502| addr->message = US"no host found for existing SMTP connection";
|
34
|
-
'notaccept' => [
|
35
|
-
'an MX or SRV record indicated no SMTP service',
|
36
|
-
'no host found for existing SMTP connection',
|
37
|
-
],
|
38
|
-
# parser.c:666| *errorptr = string_sprintf("%s (expected word or \"<\")", *errorptr);
|
39
|
-
# parser.c:701| if(bracket_count++ > 5) FAILED(US"angle-brackets nested too deep");
|
40
|
-
# parser.c:738| FAILED(US"domain missing in source-routed address");
|
41
|
-
# parser.c:747| : string_sprintf("malformed address: %.32s may not follow %.*s",
|
42
|
-
'syntaxerror' => [
|
43
|
-
'angle-brackets nested too deep',
|
44
|
-
'expected word or "<"',
|
45
|
-
'domain missing in source-routed address',
|
46
|
-
'malformed address:',
|
47
|
-
],
|
48
|
-
# deliver.c:5614| addr->message = US"delivery to file forbidden";
|
49
|
-
# deliver.c:5624| addr->message = US"delivery to pipe forbidden";
|
50
|
-
# transports/pipe.c:1156| addr->user_message = US"local delivery failed";
|
51
|
-
'systemerror' => [
|
52
|
-
'delivery to file forbidden',
|
53
|
-
'delivery to pipe forbidden',
|
54
|
-
'local delivery failed',
|
55
|
-
'LMTP error after ',
|
56
|
-
],
|
57
|
-
# deliver.c:5425| new->message = US"Too many \"Received\" headers - suspected mail loop";
|
58
|
-
'contenterror' => ['Too many "Received" headers'],
|
59
|
-
}.freeze
|
60
|
-
DelayedFor = [
|
61
|
-
'retry timeout exceeded',
|
62
|
-
'No action is required on your part',
|
63
|
-
'retry time not reached for any host after a long failure period',
|
64
|
-
'all hosts have been failing for a long time and were last tried',
|
65
|
-
'Delay reason: ',
|
66
|
-
'has been frozen',
|
67
|
-
'was frozen on arrival by ',
|
68
|
-
].freeze
|
69
|
-
|
70
|
-
# Parse bounce messages from MXLogic
|
71
|
-
# @param [Hash] mhead Message headers of a bounce email
|
72
|
-
# @param [String] mbody Message body of a bounce email
|
73
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
74
|
-
# @return [Nil] it failed to parse or the arguments are missing
|
75
|
-
def inquire(mhead, mbody)
|
76
|
-
# X-MX-Bounce: mta/src/queue/bounce
|
77
|
-
# X-MXL-NoteHash: ffffffffffffffff-0000000000000000000000000000000000000000
|
78
|
-
# X-MXL-Hash: 4c9d4d411993da17-bbd4212b6c887f6c23bab7db4bd87ef5edc00758
|
79
|
-
match = 0
|
80
|
-
match += 1 if mhead['x-mx-bounce']
|
81
|
-
match += 1 if mhead['x-mxl-hash']
|
82
|
-
match += 1 if mhead['x-mxl-notehash']
|
83
|
-
match += 1 if mhead['from'].start_with?('Mail Delivery System')
|
84
|
-
match += 1 if ['Delivery Status Notification', 'Mail delivery failed', 'Warning: message '].any? { |a| mhead['subject'].include?(a) }
|
85
|
-
return nil unless match > 0
|
86
|
-
|
87
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
88
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
89
|
-
bodyslices = emailparts[0].split("\n")
|
90
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
91
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
92
|
-
v = nil
|
93
|
-
|
94
|
-
while e = bodyslices.shift do
|
95
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
96
|
-
# line of the beginning of the original message.
|
97
|
-
if readcursor == 0
|
98
|
-
# Beginning of the bounce message or delivery status part
|
99
|
-
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
100
|
-
next
|
101
|
-
end
|
102
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
103
|
-
next if e.empty?
|
104
|
-
|
105
|
-
# This message was created automatically by mail delivery software.
|
106
|
-
#
|
107
|
-
# A message that you sent could not be delivered to one or more of its
|
108
|
-
# recipients. This is a permanent error. The following address(es) failed:
|
109
|
-
#
|
110
|
-
# kijitora@example.jp
|
111
|
-
# SMTP error from remote mail server after RCPT TO:<kijitora@example.jp>:
|
112
|
-
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
113
|
-
v = dscontents[-1]
|
114
|
-
|
115
|
-
if e.start_with?(' <') && e.include?('@') && e.include?('>:')
|
116
|
-
# A message that you have sent could not be delivered to one or more
|
117
|
-
# recipients. This is a permanent error. The following address failed:
|
118
|
-
#
|
119
|
-
# <kijitora@example.co.jp>: 550 5.1.1 ...
|
120
|
-
if v['recipient']
|
121
|
-
# There are multiple recipient addresses in the message body.
|
122
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
123
|
-
v = dscontents[-1]
|
124
|
-
end
|
125
|
-
v['recipient'] = e[3, e.index('>:') - 3]
|
126
|
-
v['diagnosis'] = e[e.index('>:') + 3, e.size]
|
127
|
-
recipients += 1
|
128
|
-
|
129
|
-
elsif dscontents.size == recipients
|
130
|
-
# Error message
|
131
|
-
next if e.empty?
|
132
|
-
v['diagnosis'] << e + ' '
|
133
|
-
end
|
134
|
-
end
|
135
|
-
return nil unless recipients > 0
|
136
|
-
|
137
|
-
# Get the name of the local MTA
|
138
|
-
# Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
|
139
|
-
receivedby = mhead['received'] || []
|
140
|
-
recvdtoken = Sisimai::RFC5322.received(receivedby[-1])
|
141
|
-
|
142
|
-
dscontents.each do |e|
|
143
|
-
# Check the error message, the rhost, the lhost, and the smtp command.
|
144
|
-
e['lhost'] = recvdtoken[0]
|
145
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].gsub(/[-]{2}.*\z/, ''))
|
146
|
-
|
147
|
-
unless e['rhost']
|
148
|
-
# Get the remote host name
|
149
|
-
p1 = e['diagnosis'].index('host ') || -1
|
150
|
-
p2 = e['diagnosis'].index(' ', p1 + 5)
|
151
|
-
|
152
|
-
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
153
|
-
e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
|
154
|
-
e['rhost'] ||= recvdtoken[1]
|
155
|
-
end
|
156
|
-
|
157
|
-
unless e['command']
|
158
|
-
# Get the SMTP command name for the session
|
159
|
-
ReCommands.each do |r|
|
160
|
-
# Verify each regular expression of SMTP commands
|
161
|
-
if cv = e['diagnosis'].match(r)
|
162
|
-
e['command'] = cv[1].upcase
|
163
|
-
break
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# Detect the reason of bounce
|
168
|
-
if e['command'] == 'MAIL'
|
169
|
-
# MAIL | Connected to 192.0.2.135 but sender was rejected.
|
170
|
-
e['reason'] = 'rejected'
|
171
|
-
|
172
|
-
elsif %w[HELO EHLO].index(e['command'])
|
173
|
-
# HELO | Connected to 192.0.2.135 but my name was rejected.
|
174
|
-
e['reason'] = 'blocked'
|
175
|
-
else
|
176
|
-
# Verify each regular expression of session errors
|
177
|
-
MessagesOf.each_key do |r|
|
178
|
-
# Check each regular expression
|
179
|
-
next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
|
180
|
-
e['reason'] = r
|
181
|
-
break
|
182
|
-
end
|
183
|
-
|
184
|
-
unless e['reason']
|
185
|
-
# The reason "expired"
|
186
|
-
e['reason'] = 'expired' if DelayedFor.any? { |a| e['diagnosis'].include?(a) }
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
193
|
-
end
|
194
|
-
def description; return 'McAfee SaaS'; end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
@@ -1,252 +0,0 @@
|
|
1
|
-
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Office365 parses a bounce email which created by Microsoft Office 365. Methods in
|
3
|
-
# the module are called from only Sisimai::Message.
|
4
|
-
module Office365
|
5
|
-
class << self
|
6
|
-
require 'sisimai/lhost'
|
7
|
-
|
8
|
-
Indicators = Sisimai::Lhost.INDICATORS
|
9
|
-
Boundaries = ['Content-Type: message/rfc822', 'Original message headers:'].freeze
|
10
|
-
StartingOf = {
|
11
|
-
error: ['Diagnostic information for administrators:'],
|
12
|
-
eoerr: ['Original message headers:'],
|
13
|
-
}.freeze
|
14
|
-
MarkingsOf = {
|
15
|
-
eoe: %r{\A(?:
|
16
|
-
Original[ ][Mm]essage[ ][Hh]eaders:?
|
17
|
-
|Message[ ]Hops
|
18
|
-
|Cabe.+alhos[ ]originais[ ]da[ ]mensagem:
|
19
|
-
|Oorspronkelijke[ ]berichtkoppen:
|
20
|
-
)
|
21
|
-
}x,
|
22
|
-
rfc3464: %r|\AContent-Type:[ ]message/delivery-status|,
|
23
|
-
lhost: %r{\A(?:
|
24
|
-
Generating[ ]server
|
25
|
-
|Bronserver
|
26
|
-
|Servidor[ ]de[ ]origem
|
27
|
-
):[ ](.+)\z
|
28
|
-
}x,
|
29
|
-
error: %r{\A(?:
|
30
|
-
Diagnostic[ ]information[ ]for[ ]administrators:
|
31
|
-
|Error[ ]Details
|
32
|
-
|Diagnostische[ ]gegevens[ ]voor[ ]beheerders:
|
33
|
-
|Informa.+es[ ]de[ ]diagn.+stico[ ]para[ ]administradores:
|
34
|
-
)
|
35
|
-
}x,
|
36
|
-
message: %r{\A(?:
|
37
|
-
Delivery[ ]has[ ]failed[ ]to[ ]these[ ]recipients[ ]or[ ]groups:
|
38
|
-
|Original[ ]Message[ ]Details
|
39
|
-
|.+[ ]rejected[ ]your[ ]message[ ]to[ ]the[ ]following[ ]e[-]?mail[ ]addresses:
|
40
|
-
|Falha[ ]na[ ]entrega[ ]a[ ]estes[ ]destinat.+rios[ ]ou[ ]grupos:
|
41
|
-
|Uw[ ]bericht[ ]kan[ ]niet[ ]worden[ ]bezorgd[ ]bij[ ]de[ ]volgende[ ]geadresseerden[ ]of[ ]groepen:
|
42
|
-
)
|
43
|
-
}x,
|
44
|
-
}.freeze
|
45
|
-
Headers365 = %w[
|
46
|
-
x-ms-exchange-message-is-ndr
|
47
|
-
x-microsoft-antispam-prvs
|
48
|
-
x-exchange-antispam-report-test
|
49
|
-
x-exchange-antispam-report-cfa-test
|
50
|
-
x-ms-exchange-crosstenant-originalarrivaltime
|
51
|
-
x-ms-exchange-crosstenant-fromentityheader
|
52
|
-
x-ms-exchange-transport-crosstenantheadersstamped
|
53
|
-
]
|
54
|
-
StatusList = {
|
55
|
-
# https://support.office.com/en-us/article/Email-non-delivery-reports-in-Office-365-51daa6b9-2e35-49c4-a0c9-df85bf8533c3
|
56
|
-
%r/\A4[.]4[.]7\z/ => 'expired',
|
57
|
-
%r/\A4[.]4[.]312\z/ => 'networkerror',
|
58
|
-
%r/\A4[.]4[.]316\z/ => 'expired',
|
59
|
-
%r/\A4[.]7[.]26\z/ => 'authfailure',
|
60
|
-
%r/\A4[.]7[.][56]\d\d\z/ => 'blocked',
|
61
|
-
%r/\A4[.]7[.]8[5-9]\d\z/ => 'blocked',
|
62
|
-
%r/\A5[.]0[.]350\z/ => 'contenterror',
|
63
|
-
%r/\A5[.]1[.]10\z/ => 'userunknown',
|
64
|
-
%r/\A5[.]4[.]1\z/ => 'norelaying',
|
65
|
-
%r/\A5[.]4[.]312\z/ => 'networkerror',
|
66
|
-
%r/\A5[.]4[.]316\z/ => 'expired',
|
67
|
-
%r/\A5[.]4[.]6\z/ => 'networkerror',
|
68
|
-
%r/\A5[.]6[.]11\z/ => 'contenterror',
|
69
|
-
%r/\A5[.]7[.]1\z/ => 'rejected',
|
70
|
-
%r/\A5[.]7[.]1[23]\z/ => 'rejected',
|
71
|
-
%r/\A5[.]7[.]124\z/ => 'rejected',
|
72
|
-
%r/\A5[.]7[.]13[3-6]\z/ => 'rejected',
|
73
|
-
%r/\A5[.]7[.]23\z/ => 'authfailure',
|
74
|
-
%r/\A5[.]7[.]25\z/ => 'networkerror',
|
75
|
-
%r/\A5[.]7[.]50[1-3]\z/ => 'spamdetected',
|
76
|
-
%r/\A5[.]7[.]50[4-5]\z/ => 'filtered',
|
77
|
-
%r/\A5[.]7[.]50[6-7]\z/ => 'blocked',
|
78
|
-
%r/\A5[.]7[.]508\z/ => 'toomanyconn',
|
79
|
-
%r/\A5[.]7[.]509\z/ => 'authfailure',
|
80
|
-
%r/\A5[.]7[.]510\z/ => 'notaccept',
|
81
|
-
%r/\A5[.]7[.]511\z/ => 'rejected',
|
82
|
-
%r/\A5[.]7[.]512\z/ => 'authfailure',
|
83
|
-
%r/\A5[.]7[.]57\z/ => 'securityerror',
|
84
|
-
%r/\A5[.]7[.]60[6-9]\z/ => 'blocked',
|
85
|
-
%r/\A5[.]7[.]6[1-4]\d\z/ => 'blocked',
|
86
|
-
%r/\A5[.]7[.]7[0-4]\d\z/ => 'toomanyconn',
|
87
|
-
}.freeze
|
88
|
-
ReCommands = {
|
89
|
-
RCPT: %r/unknown recipient or mailbox unavailable ->.+[<]?.+[@].+[.][a-zA-Z]+[>]?/,
|
90
|
-
}.freeze
|
91
|
-
|
92
|
-
# Parse bounce messages from Microsoft Office 365
|
93
|
-
# @param [Hash] mhead Message headers of a bounce email
|
94
|
-
# @param [String] mbody Message body of a bounce email
|
95
|
-
# @return [Hash] Bounce data list and message/rfc822 part
|
96
|
-
# @return [Nil] it failed to parse or the arguments are missing
|
97
|
-
def inquire(mhead, mbody)
|
98
|
-
# X-MS-Exchange-Message-Is-Ndr:
|
99
|
-
# X-Microsoft-Antispam-PRVS: <....@...outlook.com>
|
100
|
-
# X-Exchange-Antispam-Report-Test: UriScan:;
|
101
|
-
# X-Exchange-Antispam-Report-CFA-Test:
|
102
|
-
# X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Apr 2015 23:34:45.6789 (JST)
|
103
|
-
# X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted
|
104
|
-
# X-MS-Exchange-Transport-CrossTenantHeadersStamped: ...
|
105
|
-
tryto = %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/
|
106
|
-
match = 0
|
107
|
-
match += 1 if mhead['subject'].include?('Undeliverable:')
|
108
|
-
match += 1 if mhead['subject'].include?('Onbestelbaar:')
|
109
|
-
match += 1 if mhead['subject'].include?('Não_entregue:')
|
110
|
-
|
111
|
-
Headers365.each do |e|
|
112
|
-
next if mhead[e].nil?
|
113
|
-
next if mhead[e].empty?
|
114
|
-
match += 1
|
115
|
-
end
|
116
|
-
match += 1 if mhead['received'].any? { |a| a =~ tryto }
|
117
|
-
if mhead['message-id']
|
118
|
-
# Message-ID: <00000000-0000-0000-0000-000000000000@*.*.prod.outlook.com>
|
119
|
-
match += 1 if mhead['message-id'] =~ tryto
|
120
|
-
end
|
121
|
-
return nil if match < 2
|
122
|
-
|
123
|
-
require 'sisimai/rfc1894'
|
124
|
-
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
125
|
-
permessage = {} # (Hash) Store values of each Per-Message field
|
126
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
127
|
-
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
128
|
-
bodyslices = emailparts[0].split("\n")
|
129
|
-
readcursor = 0 # (Integer) Points the current cursor position
|
130
|
-
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
131
|
-
connheader = {}
|
132
|
-
endoferror = false # (Boolean) Flag for the end of error messages
|
133
|
-
htmlbegins = false # (Boolean) Flag for HTML part
|
134
|
-
v = nil
|
135
|
-
|
136
|
-
while e = bodyslices.shift do
|
137
|
-
# Read error messages and delivery status lines from the head of the email to the previous
|
138
|
-
# line of the beginning of the original message.
|
139
|
-
if readcursor == 0
|
140
|
-
# Beginning of the bounce message or delivery status part
|
141
|
-
readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
|
142
|
-
next
|
143
|
-
end
|
144
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
145
|
-
next if e.empty?
|
146
|
-
|
147
|
-
# kijitora@example.com<mailto:kijitora@example.com>
|
148
|
-
# The email address wasn't found at the destination domain. It might
|
149
|
-
# be misspelled or it might not exist any longer. Try retyping the
|
150
|
-
# address and resending the message.
|
151
|
-
#
|
152
|
-
# Original Message Details
|
153
|
-
# Created Date: 4/29/2017 6:40:30 AM
|
154
|
-
# Sender Address: neko@example.jp
|
155
|
-
# Recipient Address: kijitora@example.org
|
156
|
-
# Subject: Nyaan#
|
157
|
-
v = dscontents[-1]
|
158
|
-
|
159
|
-
if cv = e.match(/\A.+[@].+[<]mailto:(.+[@].+)[>]\z/) ||
|
160
|
-
e.match(/\ARecipient[ ]Address:[ ]+(.+)\z/)
|
161
|
-
# kijitora@example.com<mailto:kijitora@example.com>
|
162
|
-
if v['recipient']
|
163
|
-
# There are multiple recipient addresses in the message body.
|
164
|
-
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
165
|
-
v = dscontents[-1]
|
166
|
-
end
|
167
|
-
v['recipient'] = cv[1]
|
168
|
-
recipients += 1
|
169
|
-
|
170
|
-
elsif cv = e.match(MarkingsOf[:lhost])
|
171
|
-
# Generating server: FFFFFFFFFFFF.e0.prod.outlook.com
|
172
|
-
connheader['lhost'] = cv[1].downcase
|
173
|
-
else
|
174
|
-
if endoferror
|
175
|
-
# After "Original message headers:"
|
176
|
-
next unless f = Sisimai::RFC1894.match(e)
|
177
|
-
next unless o = Sisimai::RFC1894.field(e)
|
178
|
-
next unless fieldtable[o[0]]
|
179
|
-
|
180
|
-
if v['diagnosis']
|
181
|
-
# Do not capture "Diagnostic-Code:" field because error message have already
|
182
|
-
# been captured
|
183
|
-
next if o[0] =~ /\A(?:diagnostic-code|final-recipient)\z/
|
184
|
-
v[fieldtable[o[0]]] = o[2]
|
185
|
-
|
186
|
-
next unless f
|
187
|
-
permessage[fieldtable[o[0]]] = o[2]
|
188
|
-
else
|
189
|
-
# Capture "Diagnostic-Code:" field because no error messages have been captured
|
190
|
-
v[fieldtable[o[0]]] = o[2]
|
191
|
-
permessage[fieldtable[o[0]]] = o[2]
|
192
|
-
end
|
193
|
-
else
|
194
|
-
if e =~ MarkingsOf[:error]
|
195
|
-
# Diagnostic information for administrators:
|
196
|
-
v['diagnosis'] = e
|
197
|
-
else
|
198
|
-
# kijitora@example.com
|
199
|
-
# Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipien=
|
200
|
-
# t not found by SMTP address lookup'
|
201
|
-
if v['diagnosis']
|
202
|
-
# The error message text have already captured
|
203
|
-
if e =~ MarkingsOf[:eoe]
|
204
|
-
# Original message headers:
|
205
|
-
endoferror = true
|
206
|
-
next
|
207
|
-
end
|
208
|
-
v['diagnosis'] << ' ' << e
|
209
|
-
else
|
210
|
-
# The error message text has not been captured yet
|
211
|
-
endoferror = true if e =~ MarkingsOf[:rfc3464]
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
return nil unless recipients > 0
|
218
|
-
|
219
|
-
dscontents.each do |e|
|
220
|
-
# Set default values if each value is empty.
|
221
|
-
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
222
|
-
|
223
|
-
e['status'] ||= ''
|
224
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
225
|
-
if e['status'].empty? || e['status'].end_with?('.0.0')
|
226
|
-
# There is no value of Status header or the value is 5.0.0, 4.0.0
|
227
|
-
e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || e['status']
|
228
|
-
end
|
229
|
-
|
230
|
-
ReCommands.each_key do |p|
|
231
|
-
# Try to match with regular expressions defined in ReCommands
|
232
|
-
next unless e['diagnosis'] =~ ReCommands[p]
|
233
|
-
e['command'] = p.to_s
|
234
|
-
break
|
235
|
-
end
|
236
|
-
next unless e['status']
|
237
|
-
|
238
|
-
StatusList.each_key do |f|
|
239
|
-
# Try to match with each key as a regular expression
|
240
|
-
next unless e['status'] =~ f
|
241
|
-
e['reason'] = StatusList[f]
|
242
|
-
break
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
247
|
-
end
|
248
|
-
def description; return 'Microsoft Office 365: https://office.microsoft.com/'; end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|