tuktuk 0.1.3 → 0.2.0

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/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *~
2
+ *.gem
2
3
  test
3
4
  log
4
5
  pkg
data/README.md CHANGED
@@ -19,10 +19,12 @@ To enable DKIM:
19
19
  ````
20
20
  require 'tuktuk'
21
21
 
22
- Tuktuk.dkim = {
22
+ Tuktuk.options = {
23
+ :dkim => {
23
24
  :domain => 'yoursite.com',
24
25
  :selector => 'mailer',
25
26
  :private_key => IO.read('ssl/yoursite.com.key')
27
+ }
26
28
  }
27
29
 
28
30
  email = {
@@ -35,6 +37,17 @@ To enable DKIM:
35
37
  Tuktuk.deliver(email)
36
38
  ````
37
39
 
40
+ Additional options:
41
+
42
+ ````
43
+ Tuktuk.options = {
44
+ :log_to => 'log/mailer.log',
45
+ :max_attempts => 5,
46
+ :retry_sleep => 10,
47
+ :dkim => { ... }
48
+ }
49
+ ````
50
+
38
51
  That's all.
39
52
 
40
53
  --
data/lib/tuktuk/tuktuk.rb CHANGED
@@ -7,19 +7,22 @@ require 'tuktuk/package'
7
7
  DEFAULTS = {
8
8
  :retry_sleep => 10,
9
9
  :max_attempts => 3,
10
- :mailer => "Tuktuk SMTP #{VERSION}"
10
+ :log_to => nil # $stdout
11
11
  }
12
12
 
13
13
  module Tuktuk
14
14
 
15
+ class DNSError < RuntimeError; end
16
+ class MissingFieldsError < ArgumentError; end
17
+
15
18
  class << self
16
19
 
17
20
  def deliver(message, opts = {})
18
21
  options = opts
19
22
  mail = Package.new(message)
20
- mail['X-Mailer'] = config[:mailer]
21
- lookup_and_deliver(mail)
22
- mail
23
+ mail['X-Mailer'] = "Tuktuk SMTP v#{VERSION}"
24
+ response = lookup_and_deliver(mail)
25
+ return response, mail
23
26
  end
24
27
 
25
28
  def options=(hash)
@@ -30,7 +33,6 @@ module Tuktuk
30
33
  end
31
34
 
32
35
  def dkim=(dkim_opts)
33
- # logger.info "Enabling DKIM for domain #{dkim_opts[:domain]}..."
34
36
  Dkim::domain = dkim_opts[:domain]
35
37
  Dkim::selector = dkim_opts[:selector]
36
38
  Dkim::private_key = dkim_opts[:private_key]
@@ -47,11 +49,11 @@ module Tuktuk
47
49
  end
48
50
 
49
51
  def logger
50
- @logger ||= Logger.new(config[:logfile])
52
+ @logger ||= Logger.new(config[:log_to])
51
53
  end
52
54
 
53
55
  def get_domain(email_address)
54
- email_address && email_address[/@([a-z0-9\._-]+)/i, 1]
56
+ email_address && email_address.to_s[/@([a-z0-9\._-]+)/i, 1]
55
57
  end
56
58
 
57
59
  def success(destination)
@@ -64,9 +66,8 @@ module Tuktuk
64
66
  sleep config[:retry_sleep]
65
67
  lookup_and_deliver(mail, attempt+1)
66
68
  else
67
- error_message = error.respond_to?(:message) ? "#{error.message} [#{error.class.name}]" : error
68
- logger.error("#{to} - Error: #{error_message}")
69
- raise "Unable to send to #{to}: #{error_message}"
69
+ logger.error("#{to} - Unable to send after #{attempt} attempts: #{error.message} [#{error.class.name}]")
70
+ raise error
70
71
  end
71
72
  end
72
73
 
@@ -75,51 +76,55 @@ module Tuktuk
75
76
  if mx = res.mx(domain)
76
77
  mx.sort {|x,y| x.preference <=> y.preference}.map {|rr| rr.exchange}
77
78
  else
78
- raise RuntimeError, "Could not locate MX records for domain #{domain}."
79
+ raise DNSError, "Could not locate MX records for domain #{domain}."
79
80
  end
80
81
  end
81
82
 
82
83
  def lookup_and_deliver(mail, attempt = 1)
83
- raise "No destinations found! Forgot to pass the to: field?" if mail.destinations.empty?
84
+ raise MissingFieldsError, "No destinations found! You need to pass a :to field." if mail.destinations.empty?
84
85
 
85
- mail.destinations.each do |destination|
86
+ response = nil
87
+ mail.destinations.each do |to|
86
88
 
87
- domain = get_domain(destination)
89
+ domain = get_domain(to)
88
90
  servers = smtp_servers_for_domain(domain)
89
- error(mail, destination, "Unknown host: #{domain}") && next if servers.empty?
91
+ error(mail, to, DNSError.new("Unknown host: #{domain}")) && next if servers.empty?
90
92
 
91
93
  last_error = nil
92
94
  servers.each do |server|
93
95
  begin
94
- send_now(mail, server, destination)
96
+ response = send_now(mail, server, to)
95
97
  break
96
98
  rescue => e
97
99
  last_error = e
98
100
  end
99
101
  end
100
- error(mail, destination, last_error, attempt) if last_error
102
+ error(mail, to, last_error, attempt) if last_error
101
103
  end
104
+ response
102
105
  end
103
106
 
104
107
  def send_now(mail, server, to)
105
- raw_mail = use_dkim? ? Dkim.sign(mail.to_s).to_s : mail.to_s
108
+ logger.info "#{to} - Delivering email at #{server}..."
106
109
 
110
+ raw_mail = use_dkim? ? Dkim.sign(mail.to_s).to_s : mail.to_s
107
111
  from = mail.return_path || mail.sender || mail.from_addrs.first
108
- logger.info "#{to} - Delivering email at #{server}..."
112
+ helo_domain = Dkim::domain || config[:helo_domain] || get_domain(from)
109
113
 
110
114
  context = OpenSSL::SSL::SSLContext.new
111
115
  context.verify_mode = OpenSSL::SSL::VERIFY_NONE # OpenSSL::SSL::VERIFY_PEER
112
116
 
113
- helo_domain = config[:helo_domain] || Dkim::domain || get_domain(mail[:from])
114
-
115
117
  smtp = Net::SMTP.new(server, nil)
116
118
  smtp.enable_starttls_auto(context)
119
+
120
+ response = nil
117
121
  smtp.start(helo_domain, nil, nil, nil) do |smtp|
118
- result = smtp.send_message(raw_mail, from, to)
119
- logger.info "#{to} - #{result.string.strip}"
122
+ response = smtp.send_message(raw_mail, from, to)
123
+ logger.info "#{to} - #{response.message.strip}"
120
124
  end
121
125
 
122
126
  success(to)
127
+ response
123
128
  end
124
129
 
125
130
  end
@@ -1,7 +1,7 @@
1
1
  module Tuktuk
2
2
  MAJOR = 0
3
- MINOR = 1
4
- PATCH = 3
3
+ MINOR = 2
4
+ PATCH = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].join('.')
7
7
  end
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: 29
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 3
10
- version: 0.1.3
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
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-01 00:00:00 Z
18
+ date: 2012-06-02 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: bundler