tuktuk 0.2.1 → 0.2.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.
- data/README.md +14 -6
- data/lib/tuktuk/cache.rb +28 -0
- data/lib/tuktuk/tuktuk.rb +21 -6
- data/lib/tuktuk/version.rb +1 -1
- data/tuktuk.gemspec +1 -1
- metadata +6 -5
data/README.md
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
Tuktuk - SMTP client for Ruby
|
2
2
|
=============================
|
3
3
|
|
4
|
-
|
4
|
+
Unlike Pony (which is friggin' awesome by the way) Tuktuk does not rely on
|
5
|
+
`sendmail` or a separate SMTP server in order to send email. Tuktuk looks up the
|
6
|
+
MX servers of the destination address and connects directly using Net::SMTP.
|
7
|
+
This way you don't need to install Exim or Postfix and you can actually handle
|
8
|
+
response status codes -- like bounces, 5xx -- within your application.
|
9
|
+
|
10
|
+
Plus, it supports DKIM out of the box.
|
11
|
+
|
12
|
+
``` ruby
|
5
13
|
require 'tuktuk'
|
6
14
|
|
7
15
|
email = {
|
@@ -12,11 +20,11 @@ Tuktuk - SMTP client for Ruby
|
|
12
20
|
}
|
13
21
|
|
14
22
|
Tuktuk.deliver(email)
|
15
|
-
|
23
|
+
```
|
16
24
|
|
17
25
|
To enable DKIM:
|
18
26
|
|
19
|
-
|
27
|
+
``` ruby
|
20
28
|
require 'tuktuk'
|
21
29
|
|
22
30
|
Tuktuk.options = {
|
@@ -35,18 +43,18 @@ To enable DKIM:
|
|
35
43
|
}
|
36
44
|
|
37
45
|
Tuktuk.deliver(email)
|
38
|
-
|
46
|
+
```
|
39
47
|
|
40
48
|
Additional options:
|
41
49
|
|
42
|
-
|
50
|
+
``` ruby
|
43
51
|
Tuktuk.options = {
|
44
52
|
:log_to => 'log/mailer.log',
|
45
53
|
:max_attempts => 5,
|
46
54
|
:retry_sleep => 10,
|
47
55
|
:dkim => { ... }
|
48
56
|
}
|
49
|
-
|
57
|
+
```
|
50
58
|
|
51
59
|
That's all.
|
52
60
|
|
data/lib/tuktuk/cache.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Cache
|
2
|
+
|
3
|
+
attr_reader :store, :max_keys
|
4
|
+
|
5
|
+
def initialize(max_keys = 1000)
|
6
|
+
@store = {}
|
7
|
+
@max_keys = max_keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(key)
|
11
|
+
store[key]
|
12
|
+
end
|
13
|
+
|
14
|
+
def set(key, value)
|
15
|
+
return if store[key] == value
|
16
|
+
pop if store.length > max_keys
|
17
|
+
store[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def pop
|
21
|
+
store.delete(store.keys.last)
|
22
|
+
end
|
23
|
+
|
24
|
+
def show
|
25
|
+
store.each { |k,v| puts "#{k} -> #{v}" }; nil
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/tuktuk/tuktuk.rb
CHANGED
@@ -3,10 +3,12 @@ require 'net/dns/resolver'
|
|
3
3
|
require 'dkim'
|
4
4
|
require 'logger'
|
5
5
|
require 'tuktuk/package'
|
6
|
+
require 'tuktuk/cache'
|
6
7
|
|
7
8
|
DEFAULTS = {
|
8
9
|
:retry_sleep => 10,
|
9
10
|
:max_attempts => 3,
|
11
|
+
:read_timeout => nil,
|
10
12
|
:verify_ssl => true,
|
11
13
|
:log_to => nil # $stdout,
|
12
14
|
}
|
@@ -18,6 +20,10 @@ module Tuktuk
|
|
18
20
|
|
19
21
|
class << self
|
20
22
|
|
23
|
+
def cache
|
24
|
+
@cache ||= Cache.new(100)
|
25
|
+
end
|
26
|
+
|
21
27
|
def deliver(message, opts = {})
|
22
28
|
self.options = opts if opts.any?
|
23
29
|
mail = Package.new(message)
|
@@ -61,8 +67,8 @@ module Tuktuk
|
|
61
67
|
logger.info("#{to} - Successfully sent!")
|
62
68
|
end
|
63
69
|
|
64
|
-
def error(mail, to, error, attempt
|
65
|
-
if attempt
|
70
|
+
def error(mail, to, error, attempt)
|
71
|
+
if attempt < config[:max_attempts] and (error.is_a?(EOFError) || error.is_a?(TimeoutError))
|
66
72
|
logger.info "#{to} - Got #{error.class.name} error. Retrying after #{config[:retry_sleep]} secs..."
|
67
73
|
sleep config[:retry_sleep]
|
68
74
|
lookup_and_deliver(mail, attempt+1)
|
@@ -73,11 +79,19 @@ module Tuktuk
|
|
73
79
|
end
|
74
80
|
|
75
81
|
def smtp_servers_for_domain(domain)
|
76
|
-
|
77
|
-
|
82
|
+
unless servers = cache.get(domain)
|
83
|
+
if servers = lookup_smtp_servers(domain) and servers.any?
|
84
|
+
cache.set(domain, servers)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
servers
|
88
|
+
end
|
89
|
+
|
90
|
+
def lookup_smtp_servers(domain)
|
91
|
+
if mx = Net::DNS::Resolver.new.mx(domain)
|
78
92
|
mx.sort {|x,y| x.preference <=> y.preference}.map {|rr| rr.exchange}
|
79
93
|
else
|
80
|
-
raise DNSError, "
|
94
|
+
raise DNSError, "No MX records found for domain #{domain}."
|
81
95
|
end
|
82
96
|
end
|
83
97
|
|
@@ -89,7 +103,7 @@ module Tuktuk
|
|
89
103
|
|
90
104
|
domain = get_domain(to)
|
91
105
|
servers = smtp_servers_for_domain(domain)
|
92
|
-
error(mail, to, DNSError.new("Unknown host: #{domain}")) && next if servers.empty?
|
106
|
+
error(mail, to, DNSError.new("Unknown host: #{domain}"), attempt) && next if servers.empty?
|
93
107
|
|
94
108
|
last_error = nil
|
95
109
|
servers.each do |server|
|
@@ -118,6 +132,7 @@ module Tuktuk
|
|
118
132
|
|
119
133
|
smtp = Net::SMTP.new(server, nil)
|
120
134
|
smtp.enable_starttls_auto(context)
|
135
|
+
smtp.read_timeout = config[:read_timeout] if config[:read_timeout]
|
121
136
|
|
122
137
|
response = nil
|
123
138
|
smtp.start(helo_domain, nil, nil, nil) do |smtp|
|
data/lib/tuktuk/version.rb
CHANGED
data/tuktuk.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ['tomas@forkhq.com']
|
10
10
|
s.homepage = "https://github.com/tomas/tuktuk"
|
11
11
|
s.summary = "SMTP client for Ruby with DKIM support."
|
12
|
-
s.description = "Easy way of sending DKIM-signed emails from Ruby, no
|
12
|
+
s.description = "Easy way of sending DKIM-signed emails from Ruby, no dependencies needed."
|
13
13
|
|
14
14
|
s.required_rubygems_version = ">= 1.3.6"
|
15
15
|
s.rubyforge_project = "tuktuk"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tuktuk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Tom\xC3\xA1s Pollak"
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-07-13 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bundler
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
version: 0.0.2
|
81
81
|
type: :runtime
|
82
82
|
version_requirements: *id004
|
83
|
-
description: Easy way of sending DKIM-signed emails from Ruby, no
|
83
|
+
description: Easy way of sending DKIM-signed emails from Ruby, no dependencies needed.
|
84
84
|
email:
|
85
85
|
- tomas@forkhq.com
|
86
86
|
executables: []
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- README.md
|
96
96
|
- Rakefile
|
97
97
|
- lib/tuktuk.rb
|
98
|
+
- lib/tuktuk/cache.rb
|
98
99
|
- lib/tuktuk/package.rb
|
99
100
|
- lib/tuktuk/tuktuk.rb
|
100
101
|
- lib/tuktuk/version.rb
|