sisimai 4.25.16 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +412 -393
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +15 -15
- data/README-JA.md +140 -78
- data/README.md +290 -143
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +23 -18
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -326
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -45
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +12 -12
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +41 -20
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
module Sisimai
|
2
|
+
module SMTP
|
3
|
+
# Sisimai::SMTP::Transcript is a parser for transcript logs of SMTP session
|
4
|
+
module Transcript
|
5
|
+
class << self
|
6
|
+
require 'sisimai/smtp/reply'
|
7
|
+
require 'sisimai/smtp/status'
|
8
|
+
|
9
|
+
# Parse a transcript of an SMTP session and makes structured data
|
10
|
+
# @param [String] argv0 A transcript text MTA returned
|
11
|
+
# @param [String] argv1 A label string of a SMTP client
|
12
|
+
# @apram [String] argv2 A label string of a SMTP server
|
13
|
+
# @return [Array] Structured data
|
14
|
+
# [Nil] Failed to parse or the 1st argument is missing
|
15
|
+
# @since v5.0.0
|
16
|
+
def rise(argv0 = '', argv1 = '>>>', argv2 = '<<<')
|
17
|
+
return nil if argv0.size == 0
|
18
|
+
|
19
|
+
# 1. Replace label strings of SMTP client/server at the each line
|
20
|
+
argv0.gsub!(/^[ ]+#{argv1}\s+/m, '>>> '); return nil unless argv0.include?('>>> ')
|
21
|
+
argv0.gsub!(/^[ ]+#{argv2}\s+/m, '<<< '); return nil unless argv0.include?('<<< ')
|
22
|
+
|
23
|
+
# 2. Remove strings until the first '<<<' or '>>>'
|
24
|
+
esmtp = []
|
25
|
+
table = lambda do
|
26
|
+
return {
|
27
|
+
'command' => nil, # SMTP command
|
28
|
+
'argument' => '', # An argument of each SMTP command sent from a client
|
29
|
+
'parameter' => {}, # Parameter pairs of the SMTP command
|
30
|
+
'response' => { # A Response from an SMTP server
|
31
|
+
'reply' => '', # - SMTP reply code such as 550
|
32
|
+
'status' => '', # - SMTP status such as 5.1.1
|
33
|
+
'text' => [], # - Response text lines
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
parameters = '' # Command parameters of MAIL, RCPT
|
38
|
+
cursession = nil # Current session for $esmtp
|
39
|
+
|
40
|
+
cv = ''
|
41
|
+
p0 = argv0.index('<<<') || -1 # Server response
|
42
|
+
p1 = argv0.index('>>>') || -1 # Sent command
|
43
|
+
if p0 < p1
|
44
|
+
# An SMTP server response starting with '<<<' is the first
|
45
|
+
esmtp << table.call
|
46
|
+
cursession = esmtp[-1]
|
47
|
+
cursession['command'] = 'CONN'
|
48
|
+
argv0 = argv0[p0, argv0.size] if p0 > -1
|
49
|
+
else
|
50
|
+
# An SMTP command starting with '>>>' is the first
|
51
|
+
argv0 = argv0[p1, argv0.size] if p1 > -1
|
52
|
+
end
|
53
|
+
|
54
|
+
# 3. Remove unused lines, concatenate folded lines
|
55
|
+
argv0 = argv0[0, argv0.index("\n\n") - 1] # Remove strings from the first blank line to the tail
|
56
|
+
argv0.gsub!(/\n[ ]+/m, ' ') # Concatenate folded lines to each previous line
|
57
|
+
|
58
|
+
argv0.split("\n").each do |e|
|
59
|
+
# 4. Read each SMTP command and server response
|
60
|
+
if e.start_with?('>>> ')
|
61
|
+
# SMTP client sent a command ">>> SMTP-command arguments"
|
62
|
+
if cv = e.match(/\A>>>[ ]([A-Z]+)[ ]?(.*)\z/)
|
63
|
+
# >>> SMTP Command
|
64
|
+
thecommand = cv[1]
|
65
|
+
commandarg = cv[2]
|
66
|
+
|
67
|
+
esmtp << table.call
|
68
|
+
cursession = esmtp[-1]
|
69
|
+
cursession['command'] = thecommand.upcase
|
70
|
+
|
71
|
+
if thecommand =~ /\A(?:MAIL|RCPT|XFORWARD)/
|
72
|
+
# MAIL or RCPT
|
73
|
+
if cv = commandarg.match(/\A(?:FROM|TO):[ ]*<(.+[@].+)>[ ]*(.*)\z/)
|
74
|
+
# >>> MAIL FROM: <neko@example.com> SIZE=65535
|
75
|
+
# >>> RCPT TO: <kijitora@example.org>
|
76
|
+
cursession['argument'] = cv[1]
|
77
|
+
parameters = cv[2]
|
78
|
+
|
79
|
+
else
|
80
|
+
# >>> XFORWARD NAME=neko2-nyaan3.y.example.co.jp ADDR=230.0.113.2 PORT=53672
|
81
|
+
# <<< 250 2.0.0 Ok
|
82
|
+
# >>> XFORWARD PROTO=SMTP HELO=neko2-nyaan3.y.example.co.jp IDENT=2LYC6642BLzFK3MM SOURCE=REMOTE
|
83
|
+
# <<< 250 2.0.0 Ok
|
84
|
+
parameters = commandarg
|
85
|
+
commandarg = ''
|
86
|
+
end
|
87
|
+
|
88
|
+
parameters.split(" ").each do |p|
|
89
|
+
# SIZE=22022, PROTO=SMTP, and so on
|
90
|
+
if cv = p.match(/\A([^ =]+)=([^ =]+)\z/) then cursession['parameter'][cv[1].downcase] = cv[2] end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
# HELO, EHLO, AUTH, DATA, QUIT or Other SMTP command
|
94
|
+
cursession['argument'] = commandarg
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
# SMTP server sent a response "<<< response text"
|
99
|
+
p = e.index('<<< '); next unless p == 0
|
100
|
+
|
101
|
+
e = e[4, e.size]
|
102
|
+
|
103
|
+
e.sub!(/\A<<<[ ]/, '')
|
104
|
+
if cv = e.match(/\A([2-5]\d\d)[ ]/) then cursession['response']['reply'] = cv[1] end
|
105
|
+
if cv = e.match(/\A[245]\d\d[ ]([245][.]\d{1,3}[.]\d{1,3})[ ]/) then cursession['response']['status'] = cv[1] end
|
106
|
+
cursession['response']['text'] << e
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
return nil if esmtp.size == 0
|
111
|
+
return esmtp
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
data/lib/sisimai/smtp.rb
CHANGED
data/lib/sisimai/string.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module Sisimai
|
2
2
|
# Sisimai::String provide utilities for dealing string
|
3
3
|
module String
|
4
|
-
# Imported from p5-Sisimail/lib/Sisimai/String.pm
|
5
4
|
class << self
|
6
5
|
Match = {
|
7
6
|
html: %r|<html[ >].+?</html>|im,
|
@@ -47,11 +46,81 @@ module Sisimai
|
|
47
46
|
# sweep(' neko ') #=> 'neko'
|
48
47
|
def sweep(argv1)
|
49
48
|
return argv1 unless argv1.is_a?(::String)
|
50
|
-
argv1 = argv1.chomp.squeeze(' ').
|
51
|
-
argv1 = argv1.sub(/ [-]{2,}[^
|
49
|
+
argv1 = argv1.chomp.squeeze(' ').strip
|
50
|
+
argv1 = argv1.sub(/ [-]{2,}[^ ].+\z/, '')
|
52
51
|
return argv1
|
53
52
|
end
|
54
53
|
|
54
|
+
# Check if each element of the 2nd argument is aligned in the 1st argument or not
|
55
|
+
# @param [String] argv1 String to be checked
|
56
|
+
# @param [Array] argv2 List including the ordered strings
|
57
|
+
# @return [Bool] 0, 1
|
58
|
+
# @since v5.0.0
|
59
|
+
def aligned(argv1, argv2)
|
60
|
+
return nil if argv1.to_s.empty?
|
61
|
+
return nil unless argv2.is_a? Array
|
62
|
+
return nil unless argv2.size > 1
|
63
|
+
|
64
|
+
align = -1
|
65
|
+
right = 0
|
66
|
+
argv2.each do |e|
|
67
|
+
# Get the position of each element in the 1st argument using index()
|
68
|
+
p = argv1.index(e, align + 1)
|
69
|
+
break unless p # Break this loop when there is no string in the 1st argument
|
70
|
+
align = e.length + p - 1 # There is an aligned string in the 1st argument
|
71
|
+
right += 1
|
72
|
+
end
|
73
|
+
|
74
|
+
return true if right == argv2.size
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
|
78
|
+
# Find an IPv4 address from the given string
|
79
|
+
# @param [String] argv1 String including an IPv4 address
|
80
|
+
# @return [Array] List of IPv4 addresses
|
81
|
+
# @since v5.0.0
|
82
|
+
def ipv4(argv0)
|
83
|
+
return nil if argv0.to_s.empty?
|
84
|
+
return [] if argv0.size < 7
|
85
|
+
|
86
|
+
ipv4a = []
|
87
|
+
%w|( ) [ ]|.each do |e|
|
88
|
+
# Rewrite: "mx.example.jp[192.0.2.1]" => "mx.example.jp 192.0.2.1"
|
89
|
+
p0 = argv0.index(e); next unless p0
|
90
|
+
argv0[p0, 1] = ' '
|
91
|
+
end
|
92
|
+
|
93
|
+
argv0.split(' ').each do |e|
|
94
|
+
# Find string including an IPv4 address
|
95
|
+
next unless e.index('.') # IPv4 address must include "." character
|
96
|
+
|
97
|
+
lx = e.size; next if lx < 7 || lx > 17 # 0.0.0.0 = 7, [255.255.255.255] = 17
|
98
|
+
cu = 0 # Cursor for seeking each octet of an IPv4 address
|
99
|
+
as = '' # ASCII Code of each character
|
100
|
+
eo = '' # Buffer of each octet of IPv4 Address
|
101
|
+
|
102
|
+
while cu < lx
|
103
|
+
# Check whether each character is a number or "." or not
|
104
|
+
as = e[cu, 1].ord
|
105
|
+
cu += 1
|
106
|
+
|
107
|
+
if as < 48 || as > 57
|
108
|
+
# The character is not a number(0-9)
|
109
|
+
break if as != 46 # The character is not "."
|
110
|
+
next if eo == '' # The current buffer is empty
|
111
|
+
break if eo.to_i > 255 # The current buffer is greater than 255
|
112
|
+
eo = ''
|
113
|
+
next
|
114
|
+
end
|
115
|
+
eo << as.chr
|
116
|
+
break if eo.to_i > 255
|
117
|
+
end
|
118
|
+
ipv4a << e if eo.size > 0 && eo.to_i < 256
|
119
|
+
end
|
120
|
+
|
121
|
+
return ipv4a
|
122
|
+
end
|
123
|
+
|
55
124
|
# Convert given HTML text to plain text
|
56
125
|
# @param [String] argv1 HTML text
|
57
126
|
# @param [Boolean] loose Loose check flag
|
@@ -66,8 +135,8 @@ module Sisimai
|
|
66
135
|
# 3. <a href = 'http://...'>...</a> to " http://... "
|
67
136
|
# 4. <a href = 'mailto:...'>...</a> to " Value <mailto:...> "
|
68
137
|
plain.scrub!('?')
|
69
|
-
plain.gsub!(%r|<head
|
70
|
-
plain.gsub!(%r|<style
|
138
|
+
plain.gsub!(%r|<head>.+</head>|im, '')
|
139
|
+
plain.gsub!(%r|<style.+?>.+</style>|im, '')
|
71
140
|
plain.gsub!(%r|<a\s+href\s*=\s*['"](https?://.+?)['"].*?>(.*?)</a>|i, '[\2](\1)')
|
72
141
|
plain.gsub!(%r|<a\s+href\s*=\s*["']mailto:([^\s]+?)["']>(.*?)</a>|i, '[\2](mailto:\1)')
|
73
142
|
|
data/lib/sisimai/time.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'date'
|
2
2
|
module Sisimai
|
3
|
-
# Sisimai::Time is a child class of Date for Sisimai::
|
3
|
+
# Sisimai::Time is a child class of Date for Sisimai::Fact
|
4
4
|
class Time < ::DateTime
|
5
|
-
# Imported from p5-Sisimail/lib/Sisimai/Time.pm
|
6
5
|
def to_json(*)
|
7
6
|
return self.to_time.to_i
|
8
7
|
end
|
data/lib/sisimai/version.rb
CHANGED
data/lib/sisimai.rb
CHANGED
@@ -1,46 +1,59 @@
|
|
1
|
-
# Sisimai is
|
2
|
-
#
|
3
|
-
# also available if "YAML" module is installed on your system) from parsed bounce
|
4
|
-
# messages. Sisimai is a coined word: Sisi (the number 4 is pronounced "Si" in
|
5
|
-
# Japanese) and MAI (acronym of "Mail Analyzing Interface").
|
1
|
+
# Sisimai is a Ruby module for analyzing RFC5322 bounce emails and generating structured data from
|
2
|
+
# parsed results.
|
6
3
|
require 'sisimai/version'
|
7
4
|
module Sisimai
|
8
|
-
# Imported from p5-Sisimail/lib/Sisimai.pm
|
9
5
|
class << self
|
10
6
|
def version(); return Sisimai::VERSION; end
|
11
|
-
def sysname(); return 'bouncehammer'; end
|
12
7
|
def libname(); return 'Sisimai'; end
|
13
8
|
|
9
|
+
# Emulate "rise" method for the backward compatible
|
10
|
+
def make(argv0, **argv1)
|
11
|
+
warn ' ***warning: Sisimai.make will be removed at v5.1.0. Use Sisimai.rise instead';
|
12
|
+
return Sisimai.rise(argv0, **argv1)
|
13
|
+
end
|
14
|
+
|
14
15
|
# Wrapper method for parsing mailbox/maidir
|
15
16
|
# @param [String] argv0 Path to mbox or Maildir/
|
16
17
|
# @param [Hash] argv0 or Hash (decoded JSON)
|
17
18
|
# @param [IO] argv0 or STDIN object
|
18
19
|
# @param [Hash] argv1 Parser options(delivered=false)
|
19
20
|
# @options argv1 [Boolean] delivered true: Include "delivered" reason
|
20
|
-
# @options argv1 [
|
21
|
+
# @options argv1 [Boolean] vacation true: Include "vacation" reason
|
22
|
+
# @options argv1 [Array] c___ Proc object to a callback method for the message and each file
|
21
23
|
# @return [Array] Parsed objects
|
22
24
|
# @return [nil] nil if the argument was wrong or an empty array
|
23
|
-
def
|
25
|
+
def rise(argv0, **argv1)
|
24
26
|
return nil unless argv0
|
25
|
-
require 'sisimai/data'
|
26
|
-
require 'sisimai/message'
|
27
27
|
require 'sisimai/mail'
|
28
|
+
require 'sisimai/fact'
|
28
29
|
|
29
|
-
list = []
|
30
30
|
return nil unless mail = Sisimai::Mail.new(argv0)
|
31
|
+
kind = mail.kind
|
32
|
+
c___ = argv1[:c___].is_a?(Array) ? argv1[:c___] : [nil, nil]
|
33
|
+
sisi = []
|
34
|
+
|
31
35
|
while r = mail.data.read do
|
32
36
|
# Read and parse each email file
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
path = mail.data.path
|
38
|
+
args = { data: r, hook: c___[0], origin: path, delivered: argv1[:delivered], vacation: argv1[:vacation] }
|
39
|
+
fact = Sisimai::Fact.rise(**args) || []
|
40
|
+
|
41
|
+
if c___[1]
|
42
|
+
# Run the callback function specified with "c___" parameter of Sisimai.rise after reading
|
43
|
+
# each email file in Maildir/ every time
|
44
|
+
args = { 'kind' => kind, 'mail' => r, 'path' => path, 'fact' => fact }
|
45
|
+
begin
|
46
|
+
c___[1].call(args) if c___[1].is_a?(Proc)
|
47
|
+
rescue StandardError => ce
|
48
|
+
warn ' ***warning: Something is wrong in the second element of the ":c___":' << ce.to_s
|
49
|
+
end
|
50
|
+
end
|
36
51
|
|
37
|
-
|
38
|
-
next unless data = Sisimai::Data.make(**methodargv)
|
39
|
-
list += data unless data.empty?
|
52
|
+
sisi += fact unless fact.empty?
|
40
53
|
end
|
41
54
|
|
42
|
-
return nil if
|
43
|
-
return
|
55
|
+
return nil if sisi.empty?
|
56
|
+
return sisi
|
44
57
|
end
|
45
58
|
|
46
59
|
# Wrapper method to parse mailbox/Maildir and dump as JSON
|
@@ -49,12 +62,13 @@ module Sisimai
|
|
49
62
|
# @param [IO] argv0 or STDIN object
|
50
63
|
# @param [Hash] argv1 Parser options
|
51
64
|
# @options argv1 [Integer] delivered true: Include "delivered" reason
|
65
|
+
# @options argv1 [Integer] vacation true: Include "vacation" reason
|
52
66
|
# @options argv1 [Lambda] hook Lambda object to be called back
|
53
67
|
# @return [String] Parsed data as JSON text
|
54
68
|
def dump(argv0, **argv1)
|
55
69
|
return nil unless argv0
|
70
|
+
nyaan = Sisimai.rise(argv0, **argv1) || []
|
56
71
|
|
57
|
-
nyaan = Sisimai.make(argv0, **argv1) || []
|
58
72
|
if RUBY_PLATFORM.start_with?('java')
|
59
73
|
# java-based ruby environment like JRuby.
|
60
74
|
require 'jrjackson'
|
@@ -16,7 +16,10 @@ Received: from mailgw.example.co.jp (mx [192.0.2.98])
|
|
16
16
|
From: Postmaster@example.co.jp
|
17
17
|
To: "Neko" <kijitora@example.org>
|
18
18
|
Subject: DELIVERY FAILURE:
|
19
|
-
|
19
|
+
=?ISO-2022-JP?B?GyRCJWYhPCU2ITwbKEI=?= Neko (kijitora@example.co.jp)
|
20
|
+
=?US-ASCII?Q??=
|
21
|
+
=?ISO-2022-JP?B?GyRCJE8bKEI=?= Domino =?ISO-2022-JP?B?GyRCJUclIyVsGyhC?=
|
22
|
+
=?ISO-2022-JP?B?GyRCJS8lSCVqJEskTzgrJEQkKyRqJF4kOyRzISMbKEI=?=
|
20
23
|
Date: Thu, 08 Jul 2012 00:03:54 +0800
|
21
24
|
MIME-Version: 1.0
|
22
25
|
X-Priority: 3 (Normal)
|
@@ -40,7 +43,7 @@ was not delivered to:
|
|
40
43
|
|
41
44
|
because:
|
42
45
|
|
43
|
-
|
46
|
+
$B%f!<%6!<(B Neko (kijitora@example.co.jp) $B$O(B Domino $B%G%#%l%/%H%j$K$O8+$D$+$j$^$;$s!#(B
|
44
47
|
|
45
48
|
|
46
49
|
--==0000000000000000000000
|
@@ -51,7 +54,7 @@ Reporting-MTA: dns;mx.example.co.jp
|
|
51
54
|
Final-Recipient: rfc822;kijitora@example.co.jp
|
52
55
|
Action: failed
|
53
56
|
Status: 5.0.0
|
54
|
-
Diagnostic-Code: X-Notes;
|
57
|
+
Diagnostic-Code: X-Notes; $B%f!<%6!<(BNeko (kijitora@example.co.jp) $B$O(B Domino $B%G%#%l%/%H%j$K$O8+$D$+$j$^$;$s!#(B
|
55
58
|
|
56
59
|
--==0000000000000000000000
|
57
60
|
Content-Type: message/rfc822
|
@@ -0,0 +1,174 @@
|
|
1
|
+
Delivered-To: kijitora-cat-neko-nyaan@google.example.com
|
2
|
+
Received: by 2002:ab2:1785:0:b0:19a:50ce:a944 with SMTP id x5csp577194lqe;
|
3
|
+
Thu, 26 Feb 2023 18:30:56 -0800 (PST)
|
4
|
+
X-Received: by 2002:a05:651c:2228:b0:295:9c2e:7324 with SMTP id y40-20020a05651c222800b002959c2e7324mr6911855ljq.4.1677465056139;
|
5
|
+
Thu, 26 Feb 2023 18:30:56 -0800 (PST)
|
6
|
+
ARC-Seal: i=1; a=rsa-sha256; t=1677465056; cv=none;
|
7
|
+
d=google.com; s=arc-20160816;
|
8
|
+
b=OP8D/87B1NpWlJIFLb1Ryp9sBLMQEn0UmitQx/lhOphS5Y7h5VMQdue/m03cyueBqh
|
9
|
+
zWoeGi5vFkSzfqkopcggWfv26ZjF7ECHEWTULvw1Ddf1XqErTWOR9zjoxI5U71Kjg3CA
|
10
|
+
2JtSCWTN2JG81XAnspYKc2qX7UUPISnl6mP5NjKzuDyHQKE3AtCHaAvy+/zUIXNfGZC5
|
11
|
+
VQVXi8C0cYMPMkFfh6qBlU64K9D5H+m4XB12tkRYzhejyAVz1z0UkgPcazLiqvCIPf5d
|
12
|
+
5AajrntYaTvOar/K8+F1X3TYucNmWfGyXzPcBfCy6OjsdF4WUJ+P4WyPkcC4ZMnQuzTF
|
13
|
+
eemA==
|
14
|
+
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
|
15
|
+
h=in-reply-to:references:subject:from:date:message-id:auto-submitted
|
16
|
+
:to:dkim-signature;
|
17
|
+
bh=o7cpmqx+tgCx5m+g8oZRWsGCIo8X32S8zBkahP2egx0=;
|
18
|
+
b=qp3ixYdgDwSmM9zTspitM3aUqmuQqGf52SlCuvGRrjksgHbHoSY6jRljQpWPDkwUlR
|
19
|
+
LdN/dyIBBmx2HqnVEjcwaajj52M+wJdQAdGj7gu2g+SP06VpmW+szmuMtqC13cJqlNhd
|
20
|
+
VJ67sS7oBJVRm4Jy5RmE2lfpnPMduLKo4MKQc6Uj7yxkeQlP4iNCVPfp1McXyhxtFHns
|
21
|
+
KogLbkS8NFpA04RaC4tabvp4vDup1/bFS/JRPBE4IQiYyUqVrG8s7o/0U5DznTy3Zsgf
|
22
|
+
zpxCIWd9zYzzmWFeKdyJNmAaH6e7/s+5rQVGe/ryc2q4lPNadxPcsMjOoJ2d29RCyFMy
|
23
|
+
/q0A==
|
24
|
+
ARC-Authentication-Results: i=1; mx.google.com;
|
25
|
+
dkim=pass header.i=@googlemail.com header.s=20210112 header.b=PqBP51+l;
|
26
|
+
spf=none (google.com: mail-sor-f69.google.com does not designate permitted sender hosts) smtp.helo=mail-sor-f69.google.com;
|
27
|
+
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com
|
28
|
+
Return-Path: <>
|
29
|
+
Received: from mail-sor-f69.google.com (mail-sor-f69.google.com. [209.85.220.69])
|
30
|
+
by mx.google.com with SMTPS id q4-20020a2e9144000000b002946a078ae0sor1225584ljg.16.2023.02.26.18.30.56
|
31
|
+
for <kijitora-cat-neko-nyaan@google.example.com>
|
32
|
+
(Google Transport Security);
|
33
|
+
Thu, 26 Feb 2023 18:30:56 -0800 (PST)
|
34
|
+
Received-SPF: none (google.com: mail-sor-f69.google.com does not designate permitted sender hosts) client-ip=209.85.220.69;
|
35
|
+
Authentication-Results: mx.google.com;
|
36
|
+
dkim=pass header.i=@googlemail.com header.s=20210112 header.b=PqBP51+l;
|
37
|
+
spf=none (google.com: mail-sor-f69.google.com does not designate permitted sender hosts) smtp.helo=mail-sor-f69.google.com;
|
38
|
+
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com
|
39
|
+
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
40
|
+
d=googlemail.com; s=20210112;
|
41
|
+
h=in-reply-to:references:subject:from:date:message-id:auto-submitted
|
42
|
+
:to:from:to:cc:subject:date:message-id:reply-to;
|
43
|
+
bh=o7cpmqx+tgCx5m+g8oZRWsGCIo8X32S8zBkahP2egx0=;
|
44
|
+
b=PqBP51+lcin2uB1zGXsK534CFC9hpjVMDQRkzfbcTLcn9dQoqN2Mqs+6yHelWNr4eX
|
45
|
+
iZ0EVsWqfkU10OngaL9ThubvJqbYhZbc2Gcn0LdiqGrhMxPNSQ34rh/nlEODsbbJf2VW
|
46
|
+
693Q+Z2ZhhZEapenSlVZjt8yz4CRi0qTdXkUPMEAnBEMpNviY2RidqALyeGgZBO5bNCm
|
47
|
+
FJd6AqwcHWW39mkM/iogaQjVVuxS68j8RApvY45meW+2JU718KqwmjVbP2KZ/ITCjOtf
|
48
|
+
TvNrRnHviC5vlUQKpmgpA2O/IzohR+nLnZctyT0KmRFNT/64gIm0fXNtrBnO8H2h5guG
|
49
|
+
9KEg==
|
50
|
+
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
51
|
+
d=1e100.net; s=20210112;
|
52
|
+
h=in-reply-to:references:subject:from:date:message-id:auto-submitted
|
53
|
+
:to:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
|
54
|
+
bh=o7cpmqx+tgCx5m+g8oZRWsGCIo8X32S8zBkahP2egx0=;
|
55
|
+
b=A5Pr4scyEyeQ8hEk1X/11Ny4vP9lDOgOFCbADSW8su0Rq9MpPOp9qzYd85NcptzYaJ
|
56
|
+
ppKYZKCmzxoyQ3ZpPjo2EE/hXov0uG8I2uyWRuLrZETzVfIrtuWcri7E4xevduA9kdhu
|
57
|
+
nNrB9v2oFGRP5+Qz250EP2JHQLr02yLBjk7Bjz4cQDWsxGoyKLXNmLIeef84O6CgwiSp
|
58
|
+
z47l7B0D6LeL3DsUn15BVi2dPE4WNy6WayLXectHuguPV0e0MAipvveS81atFaRlgn0M
|
59
|
+
ri1GaOyX1O482y53Dzp0CxpMn4ncGjy16fiIbCYWhM1zFXWlwE0gh0KUUvIi5Ufbu8Vw
|
60
|
+
qDPQ==
|
61
|
+
X-Gm-Message-State: AO0yUKUJaTXy+S83h8MMnRXh7sfSuZ7HejgVWHxgkbSYtw+QqlbGU2lF 7AXe9LaunF0Hpx5yxJZoRdluHO2zI0nVlH5Xf5XAZw==
|
62
|
+
X-Google-Smtp-Source: AK7set/UsC/BGtW9CgmWT8fuRPR2fZ9bqAPkWp9ktaIpWH7ZEk6t6+2qHXF6VAriVlypEme5zhNO1UrtaRrYckjLRErmeFA6MB/l9as=
|
63
|
+
X-Received: by 2002:a05:651c:1614:b0:293:27a9:ef34 with SMTP id f20-20020a05651c161400b0029327a9ef34mr2807111ljq.0.1677465056065;
|
64
|
+
Thu, 26 Feb 2023 18:30:56 -0800 (PST)
|
65
|
+
Content-Type: multipart/report; boundary="000000000000ca2d9205f5a5444d"; report-type=delivery-status
|
66
|
+
To: kijitora-cat-neko-nyaan@google.example.com
|
67
|
+
Received: by 2002:a05:651c:1614:b0:293:27a9:ef34 with SMTP id f20-20020a05651c161400b0029327a9ef34mr2834317ljq.0; Thu, 26 Feb 2023 18:30:56 -0800 (PST)
|
68
|
+
Return-Path: <>
|
69
|
+
Auto-Submitted: auto-replied
|
70
|
+
Message-ID: <63fc15e0.050a0220.58de0.183e.GMR@mx.google.com>
|
71
|
+
Date: Thu, 26 Feb 2023 18:30:56 -0800 (PST)
|
72
|
+
From: Mail Delivery Subsystem <mailer-daemon@googlemail.com>
|
73
|
+
Subject: Delivery Status Notification (Failure)
|
74
|
+
X-Failed-Recipients: neko-nyaan-cat-meeting@google-groups.example.com
|
75
|
+
|
76
|
+
--000000000000ca2d9205f5a5444d
|
77
|
+
Content-Type: multipart/related; boundary="000000000000ca332c05f5a5444e"
|
78
|
+
|
79
|
+
--000000000000ca332c05f5a5444e
|
80
|
+
Content-Type: multipart/alternative; boundary="000000000000ca333105f5a5444f"
|
81
|
+
|
82
|
+
--000000000000ca333105f5a5444f
|
83
|
+
Content-Type: text/plain; charset="UTF-8"
|
84
|
+
|
85
|
+
|
86
|
+
** Message not delivered **
|
87
|
+
|
88
|
+
You're sending this from a different address or alias using the 'Send mail as' feature. The settings for your 'Send mail as' account are misconfigured or out of date. Check those settings and try resending.
|
89
|
+
|
90
|
+
Learn more here: https://support.google.com/mail/?p=CustomFromDenied
|
91
|
+
|
92
|
+
The response was:
|
93
|
+
|
94
|
+
Unspecified Error (SENT_SECOND_EHLO): Smtp server does not advertise AUTH capability
|
95
|
+
|
96
|
+
--000000000000ca333105f5a5444f
|
97
|
+
Content-Type: text/html; charset="UTF-8"
|
98
|
+
|
99
|
+
|
100
|
+
<html>
|
101
|
+
<head>
|
102
|
+
<style>
|
103
|
+
* {
|
104
|
+
font-family:Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
105
|
+
}
|
106
|
+
</style>
|
107
|
+
</head>
|
108
|
+
<body>
|
109
|
+
<table cellpadding="0" cellspacing="0" class="email-wrapper" style="padding-top:32px;background-color:#ffffff;"><tbody>
|
110
|
+
<tr><td>
|
111
|
+
<table cellpadding=0 cellspacing=0><tbody>
|
112
|
+
<tr><td style="max-width:560px;padding:24px 24px 32px;background-color:#fafafa;border:1px solid #e0e0e0;border-radius:2px">
|
113
|
+
<img style="padding:0 24px 16px 0;float:left" width=72 height=72 alt="Error Icon" src="cid:icon.png">
|
114
|
+
<table style="min-width:272px;padding-top:8px"><tbody>
|
115
|
+
<tr><td><h2 style="font-size:20px;color:#212121;font-weight:bold;margin:0">
|
116
|
+
Message not delivered
|
117
|
+
</h2></td></tr>
|
118
|
+
<tr><td style="padding-top:20px;color:#757575;font-size:16px;font-weight:normal;text-align:left">
|
119
|
+
You're sending this from a different address or alias using the 'Send mail as' feature. The settings for your 'Send mail as' account are misconfigured or out of date. Check those settings and try resending.
|
120
|
+
</td></tr>
|
121
|
+
<tr><td style="padding-top:24px;color:#4285F4;font-size:14px;font-weight:bold;text-align:left">
|
122
|
+
<a style="text-decoration:none" href="https://support.google.com/mail/?p=CustomFromDenied">LEARN MORE</a>
|
123
|
+
</td></tr>
|
124
|
+
</tbody></table>
|
125
|
+
</td></tr>
|
126
|
+
</tbody></table>
|
127
|
+
</td></tr>
|
128
|
+
<tr style="border:none;background-color:#fff;font-size:12.8px;width:90%">
|
129
|
+
<td align="left" style="padding:48px 10px">
|
130
|
+
The response was:<br/>
|
131
|
+
<p style="font-family:monospace">
|
132
|
+
Unspecified Error (SENT_SECOND_EHLO): Smtp server does not advertise AUTH capability
|
133
|
+
</p>
|
134
|
+
</td>
|
135
|
+
</tr>
|
136
|
+
</tbody></table>
|
137
|
+
</body>
|
138
|
+
</html>
|
139
|
+
|
140
|
+
--000000000000ca333105f5a5444f--
|
141
|
+
--000000000000ca332c05f5a5444e
|
142
|
+
Content-Type: image/png; name="icon.png"
|
143
|
+
Content-Disposition: attachment; filename="icon.png"
|
144
|
+
Content-Transfer-Encoding: base64
|
145
|
+
Content-ID: <icon.png>
|
146
|
+
|
147
|
+
|
148
|
+
--000000000000ca332c05f5a5444e--
|
149
|
+
--000000000000ca2d9205f5a5444d
|
150
|
+
Content-Type: message/delivery-status
|
151
|
+
|
152
|
+
|
153
|
+
--000000000000ca2d9205f5a5444d
|
154
|
+
Content-Type: message/rfc822
|
155
|
+
|
156
|
+
X-Gm-Message-State: AO0yUKVhi7hlxZPb1quoNAHFXZJYgxvbTGotZqnNumozCBfX0y128Dd7 ntdOGQFAIqeTt2XVskzfywmr4dxrTq5ZkcUjJd8=
|
157
|
+
X-Google-Smtp-Source: AK7set9BQ/++KfZD1JUmMUMiZsssix2NWMbSdwZ9fNTVQYWVFsuwS0n2iAfCxXwTBPTRWmYP524J/ncm2F65UJI4xAk=
|
158
|
+
X-Received: by 2002:a05:651c:1614:b0:293:27a9:ef34 with SMTP id f20-20020a05651c161400b0029327a9ef34mr2807080ljq.0.1677465053122; Thu, 26 Feb 2023 18:30:53 -0800 (PST)
|
159
|
+
MIME-Version: 1.0
|
160
|
+
In-Reply-To: <CAByYQsEaO0O4GgfWivReAX=r_OECkcwQgkgSbXJy7LeCm5vvNg@mail.gmail.com>
|
161
|
+
From: <michitsuna@example.jp>
|
162
|
+
Date: Mon, 27 Feb 2023 11:30:40 +0900
|
163
|
+
X-Gmail-Original-Message-ID: <CAByYQsF5qdTf_h-1AAVPW0RgR1YN+LE=+0Uv9LpQ4aA_myPtCw@mail.gmail.com>
|
164
|
+
Message-ID: <CAByYQsF5qdTf_h-1AAVPW0RgR1YN+LE=+0Uv9LpQ4aA_myPtCw@mail.gmail.com>
|
165
|
+
Subject: Nyaan
|
166
|
+
To: <nekochan@example.co.jp>
|
167
|
+
Content-Type: multipart/mixed; boundary="0000000000009d969b05f5a54484"
|
168
|
+
|
169
|
+
--0000000000009d969b05f5a54484
|
170
|
+
|
171
|
+
----- Message truncated -----
|
172
|
+
--0000000000009d969b05f5a54484--
|
173
|
+
|
174
|
+
--000000000000ca2d9205f5a5444d--
|