sisimai 4.25.3-java → 4.25.4-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sisimai might be problematic. Click here for more details.

Files changed (123) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -0
  4. data/ANALYTICAL-PRECISION +2 -4
  5. data/CONTRIBUTING +4 -0
  6. data/ChangeLog.md +39 -0
  7. data/Developers.mk +1 -72
  8. data/Makefile +4 -0
  9. data/README-JA.md +3 -0
  10. data/README.md +5 -2
  11. data/lib/sisimai.rb +4 -3
  12. data/lib/sisimai/arf.rb +6 -6
  13. data/lib/sisimai/bite.rb +8 -3
  14. data/lib/sisimai/bite/email.rb +7 -50
  15. data/lib/sisimai/bite/json.rb +5 -25
  16. data/lib/sisimai/data.rb +1 -1
  17. data/lib/sisimai/lhost.rb +101 -0
  18. data/lib/sisimai/{bite/email → lhost}/activehunter.rb +10 -10
  19. data/lib/sisimai/{bite/email → lhost}/amavis.rb +9 -9
  20. data/lib/sisimai/lhost/amazonses.rb +403 -0
  21. data/lib/sisimai/{bite/email → lhost}/amazonworkmail.rb +9 -9
  22. data/lib/sisimai/{bite/email → lhost}/aol.rb +10 -10
  23. data/lib/sisimai/{bite/email → lhost}/apachejames.rb +10 -10
  24. data/lib/sisimai/{bite/email → lhost}/bigfoot.rb +9 -9
  25. data/lib/sisimai/{bite/email → lhost}/biglobe.rb +10 -10
  26. data/lib/sisimai/{bite/email → lhost}/courier.rb +10 -10
  27. data/lib/sisimai/{bite/email → lhost}/domino.rb +9 -9
  28. data/lib/sisimai/{bite/email → lhost}/einsundeins.rb +10 -10
  29. data/lib/sisimai/{bite/email → lhost}/exchange2003.rb +9 -9
  30. data/lib/sisimai/{bite/email → lhost}/exchange2007.rb +9 -9
  31. data/lib/sisimai/{bite/email → lhost}/exim.rb +10 -10
  32. data/lib/sisimai/{bite/email → lhost}/ezweb.rb +9 -9
  33. data/lib/sisimai/{bite/email → lhost}/facebook.rb +9 -9
  34. data/lib/sisimai/{bite/email → lhost}/fml.rb +10 -10
  35. data/lib/sisimai/{bite/email → lhost}/gmx.rb +10 -10
  36. data/lib/sisimai/{bite/email → lhost}/google.rb +14 -14
  37. data/lib/sisimai/{bite/email → lhost}/gsuite.rb +10 -10
  38. data/lib/sisimai/{bite/email → lhost}/imailserver.rb +10 -10
  39. data/lib/sisimai/{bite/email → lhost}/interscanmss.rb +9 -9
  40. data/lib/sisimai/{bite/email → lhost}/kddi.rb +10 -10
  41. data/lib/sisimai/{bite/email → lhost}/mailfoundry.rb +9 -9
  42. data/lib/sisimai/{bite/email → lhost}/mailmarshalsmtp.rb +9 -9
  43. data/lib/sisimai/{bite/email → lhost}/mailru.rb +11 -11
  44. data/lib/sisimai/{bite/email → lhost}/mcafee.rb +9 -9
  45. data/lib/sisimai/{bite/email → lhost}/messagelabs.rb +9 -9
  46. data/lib/sisimai/{bite/email → lhost}/messagingserver.rb +9 -9
  47. data/lib/sisimai/{bite/email → lhost}/mfilter.rb +9 -9
  48. data/lib/sisimai/{bite/email → lhost}/mxlogic.rb +10 -10
  49. data/lib/sisimai/{bite/email → lhost}/notes.rb +9 -9
  50. data/lib/sisimai/{bite/email → lhost}/office365.rb +10 -10
  51. data/lib/sisimai/{bite/email → lhost}/opensmtpd.rb +9 -9
  52. data/lib/sisimai/{bite/email → lhost}/outlook.rb +9 -9
  53. data/lib/sisimai/{bite/email → lhost}/postfix.rb +9 -9
  54. data/lib/sisimai/{bite/email → lhost}/qmail.rb +9 -9
  55. data/lib/sisimai/{bite/email → lhost}/receivingses.rb +11 -11
  56. data/lib/sisimai/{bite/email → lhost}/sendgrid.rb +120 -11
  57. data/lib/sisimai/{bite/email → lhost}/sendmail.rb +9 -9
  58. data/lib/sisimai/{bite/email → lhost}/surfcontrol.rb +9 -9
  59. data/lib/sisimai/{bite/email → lhost}/userdefined.rb +9 -9
  60. data/lib/sisimai/{bite/email → lhost}/v5sendmail.rb +10 -10
  61. data/lib/sisimai/{bite/email → lhost}/verizon.rb +11 -11
  62. data/lib/sisimai/{bite/email → lhost}/x1.rb +9 -9
  63. data/lib/sisimai/{bite/email → lhost}/x2.rb +9 -9
  64. data/lib/sisimai/{bite/email → lhost}/x3.rb +9 -9
  65. data/lib/sisimai/{bite/email → lhost}/x4.rb +10 -10
  66. data/lib/sisimai/{bite/email → lhost}/x5.rb +9 -9
  67. data/lib/sisimai/{bite/email → lhost}/yahoo.rb +9 -9
  68. data/lib/sisimai/{bite/email → lhost}/yandex.rb +10 -10
  69. data/lib/sisimai/{bite/email → lhost}/zoho.rb +10 -10
  70. data/lib/sisimai/mda.rb +1 -1
  71. data/lib/sisimai/message.rb +535 -28
  72. data/lib/sisimai/message/email.rb +3 -454
  73. data/lib/sisimai/message/json.rb +3 -177
  74. data/lib/sisimai/order.rb +238 -4
  75. data/lib/sisimai/order/email.rb +5 -190
  76. data/lib/sisimai/order/json.rb +3 -39
  77. data/lib/sisimai/reason.rb +1 -1
  78. data/lib/sisimai/reason/norelaying.rb +1 -1
  79. data/lib/sisimai/reason/userunknown.rb +1 -1
  80. data/lib/sisimai/reason/virusdetected.rb +1 -0
  81. data/lib/sisimai/rfc1894.rb +2 -2
  82. data/lib/sisimai/rfc3464.rb +13 -13
  83. data/lib/sisimai/rfc3834.rb +3 -3
  84. data/lib/sisimai/rfc5322.rb +1 -1
  85. data/lib/sisimai/rhost.rb +5 -4
  86. data/lib/sisimai/rhost/exchangeonline.rb +1 -1
  87. data/lib/sisimai/rhost/franceptt.rb +1 -1
  88. data/lib/sisimai/rhost/godaddy.rb +1 -1
  89. data/lib/sisimai/rhost/iua.rb +39 -0
  90. data/lib/sisimai/version.rb +1 -1
  91. data/set-of-emails/README.md +0 -1
  92. data/set-of-emails/maildir/bsd/email-gsuite-13.eml +261 -0
  93. data/set-of-emails/maildir/bsd/email-postfix-62.eml +105 -0
  94. data/set-of-emails/maildir/bsd/email-postfix-63.eml +85 -0
  95. data/set-of-emails/maildir/bsd/rhost-iua-01.eml +70 -0
  96. metadata +75 -94
  97. data/fig/sisimai-architecture.png +0 -0
  98. data/lib/sisimai/bite/email/amazonses.rb +0 -186
  99. data/lib/sisimai/bite/json/amazonses.rb +0 -242
  100. data/lib/sisimai/bite/json/sendgrid.rb +0 -123
  101. data/set-of-emails/jsonobj/json-amazonses-01.json +0 -1
  102. data/set-of-emails/jsonobj/json-amazonses-02.json +0 -11
  103. data/set-of-emails/jsonobj/json-amazonses-03.json +0 -1
  104. data/set-of-emails/jsonobj/json-amazonses-04.json +0 -1
  105. data/set-of-emails/jsonobj/json-amazonses-05.json +0 -1
  106. data/set-of-emails/jsonobj/json-amazonses-06.json +0 -1
  107. data/set-of-emails/jsonobj/json-sendgrid-01.json +0 -1
  108. data/set-of-emails/jsonobj/json-sendgrid-02.json +0 -1
  109. data/set-of-emails/jsonobj/json-sendgrid-03.json +0 -1
  110. data/set-of-emails/jsonobj/json-sendgrid-04.json +0 -1
  111. data/set-of-emails/jsonobj/json-sendgrid-05.json +0 -1
  112. data/set-of-emails/jsonobj/json-sendgrid-06.json +0 -1
  113. data/set-of-emails/jsonobj/json-sendgrid-07.json +0 -1
  114. data/set-of-emails/jsonobj/json-sendgrid-08.json +0 -1
  115. data/set-of-emails/jsonobj/json-sendgrid-09.json +0 -1
  116. data/set-of-emails/jsonobj/json-sendgrid-10.json +0 -1
  117. data/set-of-emails/jsonobj/json-sendgrid-11.json +0 -1
  118. data/set-of-emails/jsonobj/json-sendgrid-12.json +0 -1
  119. data/set-of-emails/jsonobj/json-sendgrid-13.json +0 -1
  120. data/set-of-emails/jsonobj/json-sendgrid-14.json +0 -1
  121. data/set-of-emails/jsonobj/json-sendgrid-15.json +0 -1
  122. data/set-of-emails/jsonobj/json-sendgrid-16.json +0 -1
  123. data/set-of-emails/jsonobj/json-sendgrid-17.json +0 -1
Binary file
@@ -1,186 +0,0 @@
1
- module Sisimai::Bite::Email
2
- # Sisimai::Bite::Email::AmazonSES parses a bounce email which created by
3
- # Amazon Simple Email Service.
4
- # Methods in the module are called from only Sisimai::Message.
5
- module AmazonSES
6
- class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/AmazonSES.pm
8
- require 'sisimai/bite/email'
9
-
10
- # http://aws.amazon.com/ses/
11
- Indicators = Sisimai::Bite::Email.INDICATORS
12
- StartingOf = {
13
- message: ['The following message to <', 'An error occurred while trying to deliver the mail'],
14
- rfc822: ['content-type: message/rfc822'],
15
- }.freeze
16
- MessagesOf = { 'expired' => ['Delivery expired'] }.freeze
17
-
18
- def description; return 'Amazon SES(Sending): http://aws.amazon.com/ses/'; end
19
- def smtpagent; return Sisimai::Bite.smtpagent(self); end
20
-
21
- # X-SenderID: Sendmail Sender-ID Filter v1.0.0 nijo.example.jp p7V3i843003008
22
- # X-Original-To: 000001321defbd2a-788e31c8-2be1-422f-a8d4-cf7765cc9ed7-000000@email-bounces.amazonses.com
23
- # X-AWS-Outgoing: 199.255.192.156
24
- # X-SES-Outgoing: 2016.10.12-54.240.27.6
25
- def headerlist; return %w[x-aws-outgoing x-ses-outgoing x-amz-sns-message-id]; end
26
-
27
- # Parse bounce messages from Amazon SES
28
- # @param [Hash] mhead Message headers of a bounce email
29
- # @options mhead [String] from From header
30
- # @options mhead [String] date Date header
31
- # @options mhead [String] subject Subject header
32
- # @options mhead [Array] received Received headers
33
- # @options mhead [String] others Other required headers
34
- # @param [String] mbody Message body of a bounce email
35
- # @return [Hash, Nil] Bounce data list and message/rfc822
36
- # part or nil if it failed to parse or
37
- # the arguments are missing
38
- def scan(mhead, mbody)
39
- # :from => %r/\AMAILER-DAEMON[@]email[-]bounces[.]amazonses[.]com\z/,
40
- # :subject => %r/\ADelivery Status Notification [(]Failure[)]\z/,
41
- return nil if mhead['x-mailer'].to_s.start_with?('Amazon WorkMail')
42
-
43
- match = 0
44
- match += 1 if mhead['x-aws-outgoing']
45
- match += 1 if mhead['x-ses-outgoing']
46
- return nil unless match > 0
47
-
48
- require 'sisimai/rfc1894'
49
- fieldtable = Sisimai::RFC1894.FIELDTABLE
50
- permessage = {} # (Hash) Store values of each Per-Message field
51
-
52
- dscontents = [Sisimai::Bite.DELIVERYSTATUS]
53
- hasdivided = mbody.split("\n")
54
- havepassed = ['']
55
- rfc822list = [] # (Array) Each line in message/rfc822 part string
56
- blanklines = 0 # (Integer) The number of blank lines
57
- readcursor = 0 # (Integer) Points the current cursor position
58
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
59
- v = nil
60
-
61
- while e = hasdivided.shift do
62
- # Save the current line for the next loop
63
- havepassed << e
64
- p = havepassed[-2]
65
-
66
- if readcursor == 0
67
- # Beginning of the bounce message or message/delivery-status part
68
- if e.start_with?(StartingOf[:message][0], StartingOf[:message][1])
69
- readcursor |= Indicators[:deliverystatus]
70
- next
71
- end
72
- end
73
-
74
- if (readcursor & Indicators[:'message-rfc822']) == 0
75
- # Beginning of the original message part(message/rfc822)
76
- if e == StartingOf[:rfc822][0]
77
- readcursor |= Indicators[:'message-rfc822']
78
- next
79
- end
80
- end
81
-
82
- if readcursor & Indicators[:'message-rfc822'] > 0
83
- # message/rfc822 OR text/rfc822-headers part
84
- if e.empty?
85
- blanklines += 1
86
- break if blanklines > 1
87
- next
88
- end
89
- rfc822list << e
90
- else
91
- # message/delivery-status part
92
- next if (readcursor & Indicators[:deliverystatus]) == 0
93
- next if e.empty?
94
-
95
- if f = Sisimai::RFC1894.match(e)
96
- # "e" matched with any field defined in RFC3464
97
- next unless o = Sisimai::RFC1894.field(e)
98
- v = dscontents[-1]
99
-
100
- if o[-1] == 'addr'
101
- # Final-Recipient: rfc822; kijitora@example.jp
102
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
103
- if o[0] == 'final-recipient'
104
- # Final-Recipient: rfc822; kijitora@example.jp
105
- if v['recipient']
106
- # There are multiple recipient addresses in the message body.
107
- dscontents << Sisimai::Bite.DELIVERYSTATUS
108
- v = dscontents[-1]
109
- end
110
- v['recipient'] = o[2]
111
- recipients += 1
112
- else
113
- # X-Actual-Recipient: rfc822; kijitora@example.co.jp
114
- v['alias'] = o[2]
115
- end
116
- elsif o[-1] == 'code'
117
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
118
- v['spec'] = o[1]
119
- v['diagnosis'] = o[2]
120
- else
121
- # Other DSN fields defined in RFC3464
122
- next unless fieldtable.key?(o[0])
123
- v[fieldtable[o[0]]] = o[2]
124
-
125
- next unless f == 1
126
- permessage[fieldtable[o[0]]] = o[2]
127
- end
128
- else
129
- # Continued line of the value of Diagnostic-Code field
130
- next unless p.start_with?('Diagnostic-Code:')
131
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
132
- v['diagnosis'] << ' ' << cv[1]
133
- havepassed[-1] = 'Diagnostic-Code: ' << e
134
- end
135
- end # End of message/delivery-status
136
- end
137
-
138
- if recipients == 0 && mbody =~ /notificationType/
139
- # Try to parse with Sisimai::Bite::JSON::AmazonSES module
140
- require 'sisimai/bite/json/amazonses'
141
- j = Sisimai::Bite::JSON::AmazonSES.scan(mhead, mbody)
142
-
143
- if j['ds'].is_a? Array
144
- # Update dscontents
145
- dscontents = j['ds']
146
- recipients = j['ds'].size
147
- end
148
- end
149
- return nil unless recipients > 0
150
-
151
- dscontents.each do |e|
152
- # Set default values if each value is empty.
153
- e['lhost'] ||= permessage['rhost']
154
- permessage.each_key { |a| e[a] ||= permessage[a] || '' }
155
-
156
- e['agent'] = self.smtpagent
157
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].to_s.tr("\n", ' '))
158
-
159
- if e['status'].to_s.start_with?('5.0.0', '5.1.0', '4.0.0', '4.1.0')
160
- # Get other D.S.N. value from the error message
161
- errormessage = e['diagnosis']
162
-
163
- if cv = e['diagnosis'].match(/["'](\d[.]\d[.]\d.+)['"]/)
164
- # 5.1.0 - Unknown address error 550-'5.7.1 ...
165
- errormessage = cv[1]
166
- end
167
- e['status'] = Sisimai::SMTP::Status.find(errormessage) || e['status']
168
- end
169
-
170
- MessagesOf.each_key do |r|
171
- # Verify each regular expression of session errors
172
- next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
173
- e['reason'] = r
174
- break
175
- end
176
-
177
- end
178
-
179
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
180
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
181
- end
182
-
183
- end
184
- end
185
- end
186
-
@@ -1,242 +0,0 @@
1
- module Sisimai::Bite::JSON
2
- # Sisimai::Bite::JSON::AmazonSES parses a bounce object(JSON) which created
3
- # by Amazon Simple Email Service.
4
- # Methods in the module are called from only Sisimai::Message.
5
- module AmazonSES
6
- # Imported from p5-Sisimail/lib/Sisimai/Bite/JSON/AmazonSES.pm
7
- class << self
8
- require 'sisimai/bite/json'
9
-
10
- # https://docs.aws.amazon.com/en_us/ses/latest/DeveloperGuide/notification-contents.html
11
- BounceType = {
12
- 'Permanent' => {
13
- 'General' => '',
14
- 'NoEmail' => '',
15
- 'Suppressed' => '',
16
- },
17
- 'Transient' => {
18
- 'General' => '',
19
- 'MailboxFull' => 'mailboxfull',
20
- 'MessageTooLarge' => 'mesgtoobig',
21
- 'ContentRejected' => '',
22
- 'AttachmentRejected' => '',
23
- },
24
- }.freeze
25
-
26
- def smtpagent; return Sisimai::Bite.smtpagent(self); end
27
- def description; return 'Amazon SES(JSON): http://aws.amazon.com/ses/'; end
28
-
29
- # Parse bounce messages from Amazon SES(JSON)
30
- # @param [Hash] mhead Message headers of a bounce email
31
- # @options mhead [String] from From header
32
- # @options mhead [String] date Date header
33
- # @options mhead [String] subject Subject header
34
- # @options mhead [Array] received Received headers
35
- # @options mhead [String] others Other required headers
36
- # @param [String] mbody Message body of a bounce email
37
- # @return [Hash, Nil] Bounce data list and message/rfc822
38
- # part or nil if it failed to parse or
39
- # the arguments are missing
40
- # @since v4.20.0
41
- def scan(mhead, mbody)
42
- return nil unless mhead['x-amz-sns-message-id']
43
- return nil if mhead['x-amz-sns-message-id'].empty?
44
-
45
- hasdivided = mbody.split("\n")
46
- jsonstring = ''
47
- jsonthings = nil
48
- foldedline = false
49
-
50
- while e = hasdivided.shift do
51
- # Find JSON string from the message body
52
- next if e.empty?
53
- break if e == '--'
54
- break if e == '__END_OF_EMAIL_MESSAGE__'
55
-
56
- # The line starts with " ", continued from !\n.
57
- e.lstrip! if foldedline
58
- foldedline = false
59
-
60
- if e.end_with?('!')
61
- # ... long long line ...![\n]
62
- e.chomp!('!')
63
- foldedline = true
64
- end
65
- jsonstring << e
66
- end
67
-
68
- begin
69
- if RUBY_PLATFORM.start_with?('java')
70
- # java-based ruby environment like JRuby.
71
- require 'jrjackson'
72
- jsonobject = JrJackson::Json.load(jsonstring)
73
-
74
- # 'Message' => '{"notificationType":"Bounce",...
75
- jsonthings = JrJackson::Json.load(jsonobject['Message']) if jsonobject['Message']
76
- else
77
- # Matz' Ruby Implementation
78
- require 'oj'
79
- jsonobject = Oj.load(jsonstring)
80
-
81
- # 'Message' => '{"notificationType":"Bounce",...
82
- jsonthings = Oj.load(jsonobject['Message']) if jsonobject['Message']
83
- end
84
- jsonthings ||= jsonobject
85
-
86
- rescue StandardError => ce
87
- # Something wrong in decoding JSON
88
- warn ' ***warning: Failed to decode JSON: ' << ce.to_s
89
- return nil
90
- end
91
-
92
- return adapt(jsonthings)
93
- end
94
-
95
- # @abstract Adapt Amazon SES bounce object for Sisimai::Message format
96
- # @param [Hash] argvs bounce object(JSON) retrieved from Amazon SNS
97
- # @return [Hash, Nil] Bounce data list and message/rfc822 part or
98
- # nil if it failed to parse or the
99
- # arguments are missing
100
- # @since v4.20.0
101
- def adapt(argvs)
102
- return nil unless argvs.is_a? Hash
103
- return nil if argvs.empty?
104
- return nil unless argvs.key?('notificationType')
105
-
106
- dscontents = [Sisimai::Bite.DELIVERYSTATUS]
107
- rfc822head = {} # (Hash) Check flags for headers in RFC822 part
108
- recipients = 0 # (Integer) The number of 'Final-Recipient' header
109
- labeltable = {
110
- 'Bounce' => 'bouncedRecipients',
111
- 'Complaint' => 'complainedRecipients',
112
- }
113
- v = nil
114
-
115
- if %w[Bounce Complaint].index(argvs['notificationType'])
116
- # { "notificationType":"Bounce", "bounce": { "bounceType":"Permanent",...
117
- o = argvs[argvs['notificationType'].downcase].dup
118
- r = o[labeltable[argvs['notificationType']]] || []
119
-
120
- while e = r.shift do
121
- # 'bouncedRecipients' => [ { 'emailAddress' => 'bounce@si...' }, ... ]
122
- # 'complainedRecipients' => [ { 'emailAddress' => 'complaint@si...' }, ... ]
123
- next unless Sisimai::RFC5322.is_emailaddress(e['emailAddress'])
124
-
125
- v = dscontents[-1]
126
- if v['recipient']
127
- # There are multiple recipient addresses in the message body.
128
- dscontents << Sisimai::Bite.DELIVERYSTATUS
129
- v = dscontents[-1]
130
- end
131
- recipients += 1
132
- v['recipient'] = e['emailAddress']
133
-
134
- if argvs['notificationType'] == 'Bounce'
135
- # 'bouncedRecipients => [ {
136
- # 'emailAddress' => 'bounce@simulator.amazonses.com',
137
- # 'action' => 'failed',
138
- # 'status' => '5.1.1',
139
- # 'diagnosticCode' => 'smtp; 550 5.1.1 user unknown'
140
- # }, ... ]
141
- v['action'] = e['action']
142
- v['status'] = e['status']
143
-
144
- if cv = e['diagnosticCode'].match(/\A(.+?);[ ]*(.+)\z/)
145
- # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
146
- v['spec'] = cv[1].upcase
147
- v['diagnosis'] = cv[2]
148
- else
149
- v['diagnosis'] = e['diagnosticCode']
150
- end
151
-
152
- # 'reportingMTA' => 'dsn; a27-23.smtp-out.us-west-2.amazonses.com',
153
- if cv = o['reportingMTA'].match(/\Adsn;[ ](.+)\z/) then v['lhost'] = cv[1] end
154
-
155
- if BounceType.key?(o['bounceType']) &&
156
- BounceType[o['bounceType']].key?(o['bounceSubType'])
157
- # 'bounce' => {
158
- # 'bounceType' => 'Permanent',
159
- # 'bounceSubType' => 'General'
160
- # },
161
- v['reason'] = BounceType[o['bounceType']][o['bounceSubType']]
162
- end
163
- else
164
- # 'complainedRecipients' => [ {
165
- # 'emailAddress' => 'complaint@simulator.amazonses.com' }, ... ],
166
- v['reason'] = 'feedback'
167
- v['feedbacktype'] = o['complaintFeedbackType'] || ''
168
- end
169
-
170
- v['date'] = o['timestamp'] || argvs['mail']['timestamp']
171
- v['date'].sub!(/[.]\d+Z\z/, '')
172
- end
173
- elsif argvs['notificationType'] == 'Delivery'
174
- # { "notificationType":"Delivery", "delivery": { ...
175
- o = argvs['delivery'].dup
176
- r = o['recipients'] || []
177
-
178
- while e = r.shift do
179
- # 'delivery' => {
180
- # 'timestamp' => '2016-11-23T12:01:03.512Z',
181
- # 'processingTimeMillis' => 3982,
182
- # 'reportingMTA' => 'a27-29.smtp-out.us-west-2.amazonses.com',
183
- # 'recipients' => [
184
- # 'success@simulator.amazonses.com'
185
- # ],
186
- # 'smtpResponse' => '250 2.6.0 Message received'
187
- # },
188
- next unless Sisimai::RFC5322.is_emailaddress(e)
189
-
190
- v = dscontents[-1]
191
- if v['recipient']
192
- # There are multiple recipient addresses in the message body.
193
- dscontents << Sisimai::Bite.DELIVERYSTATUS
194
- v = dscontents[-1]
195
- end
196
- recipients += 1
197
- v['recipient'] = e
198
- v['lhost'] = o['reportingMTA'] || ''
199
- v['diagnosis'] = o['smtpResponse'] || ''
200
- v['status'] = Sisimai::SMTP::Status.find(v['diagnosis']) || ''
201
- v['replycode'] = Sisimai::SMTP::Reply.find(v['diagnosis']) || ''
202
- v['reason'] = 'delivered'
203
- v['action'] = 'deliverable'
204
-
205
- v['date'] = o['timestamp'] || argvs['mail']['timestamp']
206
- v['date'].sub!(/[.]\d+Z\z/, '')
207
- end
208
- else
209
- # The value of "notificationType" is not any of "Bounce", "Complaint",
210
- # or "Delivery".
211
- return nil
212
- end
213
- return nil unless recipients > 0
214
-
215
- dscontents.each do |e|
216
- e['agent'] = self.smtpagent
217
- end
218
-
219
- if argvs['mail']['headers']
220
- # "headersTruncated":false,
221
- # "headers":[ { ...
222
- argvs['mail']['headers'].each do |e|
223
- # 'headers' => [ { 'name' => 'From', 'value' => 'neko@nyaan.jp' }, ... ],
224
- next unless %w[From To Subject Message-ID Date].index(e['name'])
225
- rfc822head[e['name'].downcase] = e['value']
226
- end
227
- end
228
-
229
- unless rfc822head['message-id']
230
- # Try to get the value of "Message-Id".
231
- if argvs['mail']['messageId']
232
- # 'messageId' => '01010157e48f9b9b-891e9a0e-9c9d-4773-9bfe-608f2ef4756d-000000'
233
- rfc822head['message-id'] = argvs['mail']['messageId']
234
- end
235
- end
236
- return { 'ds' => dscontents, 'rfc822' => rfc822head }
237
- end
238
-
239
- end
240
- end
241
- end
242
-
@@ -1,123 +0,0 @@
1
- module Sisimai::Bite::JSON
2
- # Sisimai::Bite::JSON::SendGrid parses a bounce object(JSON) which created by
3
- # SendGrid. Methods in the module are called from only Sisimai::Message.
4
- module SendGrid
5
- # Imported from p5-Sisimail/lib/Sisimai/Bite/JSON/SendGrid.pm
6
- class << self
7
- require 'sisimai/bite/json'
8
-
9
- def smtpagent; return Sisimai::Bite.smtpagent(self); end
10
- def description; return 'SendGrid(JSON): http://sendgrid.com/'; end
11
-
12
- # @abstract Adapt SendGrid bounce object for Sisimai::Message format
13
- # @param [Hash] argvs bounce object(JSON) retrieved from SendGrid API
14
- # @return [Hash, Nil] Bounce data list and message/rfc822 part or
15
- # nil if it failed to parse or the
16
- # arguments are missing
17
- # @since v4.20.0
18
- def adapt(argvs)
19
- return nil unless argvs.is_a? Hash
20
- return nil if argvs.empty?
21
- return nil unless argvs.key?('email')
22
- return nil unless Sisimai::RFC5322.is_emailaddress(argvs['email'])
23
-
24
- dscontents = nil
25
- rfc822head = {}
26
- v = nil
27
-
28
- if argvs.key?('event')
29
- # https://sendgrid.com/docs/API_Reference/Webhooks/event.html
30
- # {
31
- # 'tls' => 0,
32
- # 'timestamp' => 1504555832,
33
- # 'event' => 'bounce',
34
- # 'email' => 'mailboxfull@example.jp',
35
- # 'ip' => '192.0.2.22',
36
- # 'sg_message_id' => '03_Wof6nRbqqzxRvLpZbfw.filter0017p3mdw1-11399-59ADB335-16.0',
37
- # 'type' => 'blocked',
38
- # 'sg_event_id' => 'S4wr46YHS0qr3BKhawTQjQ',
39
- # 'reason' => '550 5.2.2 <mailboxfull@example.jp>... Mailbox Full ',
40
- # 'smtp-id' => '<201709042010.v84KAQ5T032530@example.nyaan.jp>',
41
- # 'status' => '5.2.2'
42
- # },
43
- return nil unless %w[bounce deferred delivered spamreport].include?(argvs['event'])
44
- dscontents = [Sisimai::Bite.DELIVERYSTATUS]
45
- diagnostic = argvs['reason'] || ''
46
- diagnostic = argvs['response'] || '' if diagnostic.empty?
47
- timestamp0 = Sisimai::Time.parse(::Time.at(argvs['timestamp']).to_s)
48
- v = dscontents[-1]
49
-
50
- v['date'] = timestamp0.strftime("%a, %d %b %Y %T %z")
51
- v['agent'] = self.smtpagent
52
- v['lhost'] = argvs['ip'] || ''
53
- v['status'] = argvs['status'] || nil
54
- v['diagnosis'] = Sisimai::String.sweep(diagnostic)
55
- v['recipient'] = argvs['email']
56
-
57
- if argvs['event'] == 'delivered'
58
- # "event": "delivered"
59
- v['reason'] = 'delivered'
60
- elsif argvs['event'] == 'spamreport'
61
- # [
62
- # {
63
- # "email": "kijitora@example.com",
64
- # "timestamp": 1504837383,
65
- # "sg_message_id": "6_hrAeKvTDaB5ynBI2nbnQ.filter0002p3las1-27574-59B1FDA3-19.0",
66
- # "sg_event_id": "o70uHqbMSXOaaoveMZIjjg",
67
- # "event": "spamreport"
68
- # }
69
- # ]
70
- v['reason'] = 'feedback'
71
- v['feedbacktype'] = 'abuse'
72
- end
73
- v['status'] ||= Sisimai::SMTP::Status.find(v['diagnosis']) || ''
74
- v['replycode'] ||= Sisimai::SMTP::Reply.find(v['diagnosis']) || ''
75
-
76
- # Generate pseudo message/rfc822 part
77
- rfc822head = {
78
- 'from' => Sisimai::Address.undisclosed('s'),
79
- 'message-id' => v['sg_message_id'],
80
- }
81
- else
82
- # {
83
- # "status": "4.0.0",
84
- # "created": "2011-09-16 22:02:19",
85
- # "reason": "Unable to resolve MX host sendgrid.ne",
86
- # "email": "esting@sendgrid.ne"
87
- # },
88
- dscontents = [Sisimai::Bite.DELIVERYSTATUS]
89
- v = dscontents[-1]
90
-
91
- v['recipient'] = argvs['email']
92
- v['date'] = argvs['created'] || ''
93
-
94
- statuscode = argvs['status'] || ''
95
- diagnostic = Sisimai::String.sweep(argvs['reason']) || ''
96
-
97
- if statuscode =~ /\A[245]\d\d\z/
98
- # "status": "550"
99
- v['replycode'] = statuscode
100
-
101
- elsif statuscode =~ /\A[245][.]\d[.]\d+\z/
102
- # "status": "5.1.1"
103
- v['status'] = statuscode
104
- end
105
-
106
- v['status'] ||= Sisimai::SMTP::Status.find(diagnostic) || ''
107
- v['replycode'] ||= Sisimai::SMTP::Reply.find(diagnostic) || ''
108
- v['diagnosis'] = argvs['reason'] || ''
109
- v['agent'] = self.smtpagent
110
-
111
- # Generate pseudo message/rfc822 part
112
- rfc822head = {
113
- 'from' => Sisimai::Address.undisclosed('s'),
114
- 'date' => v['date'],
115
- }
116
- end
117
- return { 'ds' => dscontents, 'rfc822' => rfc822head }
118
- end
119
-
120
- end
121
- end
122
- end
123
-