mailbounce 0.1.1 → 0.1.2
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/CHANGELOG.md +5 -0
- data/README.md +6 -0
- data/lib/mailbounce/report.rb +29 -14
- data/lib/mailbounce/version.rb +1 -1
- data/lib/mailbounce.rb +2 -2
- data/mailbounce.gemspec +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f99ac991751ae3b826fb20a5e9e9f13c0871ef50b8957abab82daddccad242a
|
|
4
|
+
data.tar.gz: 5568d4cfaf4644bf4c984116276e0142ec1d4842bf79c6fed565f5dd965c2484
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19e7c1b2748c550f40c283841e869de952724c29defc24404a2c7d0f251f515150e59383f304261c2b71ffb4d6e66d1f587952dd2e35ac86bc4c4edc9f11b6d5
|
|
7
|
+
data.tar.gz: febb828d483008e5abcd932ed760f86db3f8cde575f32ef47ae901a89d62b66a67c8349515aadababf0950bd85c9ca256f52c6dbfc57bb293d2f88677057f0ab
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -110,6 +110,12 @@ Reports announce delays and successes by the same route and in the same shape, s
|
|
|
110
110
|
|
|
111
111
|
A report naming several recipients speaks for a given address only when it names it; one covering a single recipient needn't name anyone. Nothing raises: a report with no machine-readable part, or bytes that aren't a message at all, reports nothing.
|
|
112
112
|
|
|
113
|
+
Bounce are cappted to 1 MB. Past that a report is refused like any other it can't read. Lower it where you'd rather hold less:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
MailBounce.parse(raw_bounce, max_size: 64 * 1024)
|
|
117
|
+
```
|
|
118
|
+
|
|
113
119
|
## Testing
|
|
114
120
|
|
|
115
121
|
```sh
|
data/lib/mailbounce/report.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "mail"
|
|
2
|
+
require "set"
|
|
2
3
|
|
|
3
4
|
require "mailbounce/recipient"
|
|
4
5
|
|
|
@@ -13,6 +14,10 @@ module MailBounce
|
|
|
13
14
|
|
|
14
15
|
FIELD_NAME = /\A(?<name>[A-Za-z][A-Za-z0-9\-]*)[ \t]*:/
|
|
15
16
|
|
|
17
|
+
# A bounce is a notice, not a mailbox — Postfix caps its own at 50 KB.
|
|
18
|
+
# Anything past this is not a report anyone meant to send.
|
|
19
|
+
MAX_SIZE = 1024 * 1024
|
|
20
|
+
|
|
16
21
|
# Value stays on its line so an empty field cannot swallow the next.
|
|
17
22
|
FIELDS = {
|
|
18
23
|
action: /^Action[ \t]*:[ \t]*(?<value>.+)$/i,
|
|
@@ -23,12 +28,14 @@ module MailBounce
|
|
|
23
28
|
remote_mta: /^Remote-MTA[ \t]*:[ \t]*(?<value>.+)$/i
|
|
24
29
|
}.freeze
|
|
25
30
|
|
|
26
|
-
def self.parse(raw)
|
|
27
|
-
new(raw)
|
|
31
|
+
def self.parse(raw, max_size: MAX_SIZE)
|
|
32
|
+
new(raw, max_size: max_size)
|
|
28
33
|
end
|
|
29
34
|
|
|
30
|
-
def initialize(raw)
|
|
31
|
-
|
|
35
|
+
def initialize(raw, max_size: MAX_SIZE)
|
|
36
|
+
report = raw.to_s
|
|
37
|
+
|
|
38
|
+
@mail = Mail.new(report) if report.bytesize <= max_size
|
|
32
39
|
rescue StandardError
|
|
33
40
|
@mail = nil
|
|
34
41
|
end
|
|
@@ -83,22 +90,30 @@ module MailBounce
|
|
|
83
90
|
end
|
|
84
91
|
|
|
85
92
|
# A block ends when a field it already has reappears (order is not fixed).
|
|
93
|
+
# The names are kept rather than matched for again: a block grows, and
|
|
94
|
+
# reading all of it per line costs the square of its length.
|
|
86
95
|
def per_recipient(chunk)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
blocks, named = [], Set.new
|
|
97
|
+
|
|
98
|
+
chunk.lines.each do |line|
|
|
99
|
+
name = field_name(line)
|
|
100
|
+
|
|
101
|
+
if blocks.empty? || named.include?(name)
|
|
91
102
|
blocks << +line
|
|
103
|
+
named = Set.new
|
|
104
|
+
else
|
|
105
|
+
blocks.last << line
|
|
92
106
|
end
|
|
107
|
+
|
|
108
|
+
named << name if name
|
|
93
109
|
end
|
|
110
|
+
|
|
111
|
+
blocks
|
|
94
112
|
end
|
|
95
113
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
else
|
|
100
|
-
true
|
|
101
|
-
end
|
|
114
|
+
# Field names are case-insensitive; a continuation line has none.
|
|
115
|
+
def field_name(line)
|
|
116
|
+
line[FIELD_NAME, :name]&.downcase
|
|
102
117
|
end
|
|
103
118
|
|
|
104
119
|
def recipient_from(block)
|
data/lib/mailbounce/version.rb
CHANGED
data/lib/mailbounce.rb
CHANGED
data/mailbounce.gemspec
CHANGED
|
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = [ "Simon Lev" ]
|
|
10
10
|
|
|
11
11
|
spec.summary = "Email delivery failures for Ruby."
|
|
12
|
-
spec.description = "Answers one question about a rejected message: whose fault was it?"
|
|
12
|
+
spec.description = "Answers one question about a rejected message: whose fault was it? Parses bounces, NDRs, and DSN reports to classify delivery failures."
|
|
13
13
|
|
|
14
14
|
spec.homepage = "https://github.com/mailpiece/mailbounce"
|
|
15
15
|
spec.license = "MIT"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailbounce
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Simon Lev
|
|
@@ -23,7 +23,8 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '2.7'
|
|
26
|
-
description: 'Answers one question about a rejected message: whose fault was it?
|
|
26
|
+
description: 'Answers one question about a rejected message: whose fault was it? Parses
|
|
27
|
+
bounces, NDRs, and DSN reports to classify delivery failures.'
|
|
27
28
|
executables: []
|
|
28
29
|
extensions: []
|
|
29
30
|
extra_rdoc_files: []
|