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 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
 
@@ -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 = 1)
65
- if attempt <= config[:max_attempts] && (error.is_a?(Net::SMTPServerBusy) or error.is_a?(EOFError))
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
- res = Net::DNS::Resolver.new
77
- if mx = res.mx(domain)
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, "Could not locate MX records for domain #{domain}."
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|
@@ -1,7 +1,7 @@
1
1
  module Tuktuk
2
2
  MAJOR = 0
3
3
  MINOR = 2
4
- PATCH = 1
4
+ PATCH = 2
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].join('.')
7
7
  end
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 depenencies needed."
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: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
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-06-02 00:00:00 Z
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 depenencies needed.
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