ar_mailer 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +36 -0
- data/{LICENSE → LICENSE.txt} +3 -1
- data/Manifest.txt +4 -2
- data/{README → README.txt} +8 -2
- data/Rakefile +8 -63
- data/lib/action_mailer/ar_mailer.rb +50 -17
- data/lib/action_mailer/ar_sendmail.rb +40 -13
- data/lib/smtp_tls.rb +105 -0
- data/test/action_mailer.rb +7 -4
- data/test/test_armailer.rb +11 -0
- data/test/test_arsendmail.rb +84 -49
- metadata +33 -18
data/History.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
= 1.2.0
|
2
|
+
|
3
|
+
* Bugs fixed
|
4
|
+
* Handle SMTPServerBusy by backing off @delay seconds then re-queueing
|
5
|
+
* Allow email delivery class to be set in ARMailer.
|
6
|
+
* ar_sendmail --mailq works with --table-name now.
|
7
|
+
* Miscellaneous Updates
|
8
|
+
* Added documentation to require 'action_mailer/ar_mailer' in
|
9
|
+
instructions.
|
10
|
+
* Moved to ZSS p4 repository
|
11
|
+
* Supports TLS now. Requested by Dave Thomas. smtp_tls.rb from Kyle
|
12
|
+
Maxwell & etc.
|
13
|
+
|
14
|
+
= 1.1.0
|
15
|
+
|
16
|
+
* Features
|
17
|
+
* Added --chdir to set rails directory
|
18
|
+
* Added --environment to set RAILS_ENV
|
19
|
+
* Exits cleanly on TERM or INT signals
|
20
|
+
* Added FreeBSD rc.d script
|
21
|
+
* Exceptions during SMTP sending are now logged
|
22
|
+
* No longer waits if sending email took too long
|
23
|
+
* Bugs fixed
|
24
|
+
* Fixed last send attempt in --mailq
|
25
|
+
* Better SMTP error handling
|
26
|
+
* Messages are removed from the queue on 5xx errors
|
27
|
+
* Added Net::SMTP.reset to avoid needing to recreate the connection
|
28
|
+
|
29
|
+
= 1.0.1
|
30
|
+
|
31
|
+
* Bugs fixed
|
32
|
+
* From and to of email destination were swapped
|
33
|
+
|
34
|
+
= 1.0.0
|
35
|
+
|
36
|
+
* Birthday
|
data/{LICENSE → LICENSE.txt}
RENAMED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
Original code copyright 2006, 2007, Eric Hodel, The Robot Co-op. All
|
2
|
+
rights reserved. Some code under other license, see individual files
|
3
|
+
for details.
|
2
4
|
|
3
5
|
Redistribution and use in source and binary forms, with or without
|
4
6
|
modification, are permitted provided that the following conditions
|
data/Manifest.txt
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
History.txt
|
2
|
+
LICENSE.txt
|
2
3
|
Manifest.txt
|
3
|
-
README
|
4
|
+
README.txt
|
4
5
|
Rakefile
|
5
6
|
bin/ar_sendmail
|
6
7
|
lib/action_mailer/ar_mailer.rb
|
7
8
|
lib/action_mailer/ar_sendmail.rb
|
9
|
+
lib/smtp_tls.rb
|
8
10
|
share/ar_sendmail
|
9
11
|
test/action_mailer.rb
|
10
12
|
test/test_armailer.rb
|
data/{README → README.txt}
RENAMED
@@ -1,12 +1,18 @@
|
|
1
1
|
= ar_mailer
|
2
2
|
|
3
|
+
A two-phase delivery agent for ActionMailer
|
4
|
+
|
3
5
|
Rubyforge Project:
|
4
6
|
|
5
|
-
http://rubyforge.org/projects/
|
7
|
+
http://rubyforge.org/projects/seattlerb
|
6
8
|
|
7
9
|
Documentation:
|
8
10
|
|
9
|
-
http://
|
11
|
+
http://seattlerb.org/ar_mailer
|
12
|
+
|
13
|
+
Bugs:
|
14
|
+
|
15
|
+
http://rubyforge.org/tracker/?func=add&group_id=1513&atid=5921
|
10
16
|
|
11
17
|
== About
|
12
18
|
|
data/Rakefile
CHANGED
@@ -1,67 +1,12 @@
|
|
1
|
-
require '
|
2
|
-
require 'rake'
|
3
|
-
require 'rake/testtask'
|
4
|
-
require 'rake/rdoctask'
|
5
|
-
require 'rake/gempackagetask'
|
1
|
+
require 'hoe'
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.summary = 'A two-phase deliver agent for ActionMailer'
|
13
|
-
s.description = 'Queues emails from ActionMailer in the database and uses a separate process to send them. Reduces sending overhead when sending hundreds of emails.'
|
3
|
+
Hoe.new 'ar_mailer', '1.2.0' do |s|
|
4
|
+
s.rubyforge_name = 'seattlerb'
|
5
|
+
s.summary = s.paragraphs_of('README.txt', 1).join(' ')
|
6
|
+
s.description = s.paragraphs_of('README.txt', 9).join(' ')
|
7
|
+
s.url = s.paragraphs_of('README.txt', 5).join(' ')
|
14
8
|
s.author = 'Eric Hodel'
|
15
|
-
s.email = '
|
16
|
-
|
17
|
-
s.has_rdoc = true
|
18
|
-
s.files = File.read('Manifest.txt').split($/)
|
19
|
-
s.require_path = 'lib'
|
20
|
-
|
21
|
-
s.executables = ['ar_sendmail']
|
22
|
-
end
|
23
|
-
|
24
|
-
desc 'Run tests'
|
25
|
-
task :default => [ :test ]
|
26
|
-
|
27
|
-
Rake::TestTask.new('test') do |t|
|
28
|
-
t.libs << 'test'
|
29
|
-
t.pattern = 'test/test_*.rb'
|
30
|
-
t.verbose = true
|
31
|
-
end
|
32
|
-
|
33
|
-
desc 'Update Manifest.txt'
|
34
|
-
task :update_manifest do
|
35
|
-
sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
|
9
|
+
s.email = 'drbrain@segment7.net'
|
10
|
+
s.changes = s.paragraphs_of('History.txt', 0..1).join("\n\n")
|
36
11
|
end
|
37
12
|
|
38
|
-
desc 'Generate RDoc'
|
39
|
-
Rake::RDocTask.new :rdoc do |rd|
|
40
|
-
rd.rdoc_dir = 'doc'
|
41
|
-
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
42
|
-
rd.main = 'README'
|
43
|
-
rd.options << '-d' if `which dot` =~ /\/dot/
|
44
|
-
rd.options << '-t ar_mailer'
|
45
|
-
end
|
46
|
-
|
47
|
-
desc 'Generate RDoc for dev.robotcoop.com'
|
48
|
-
Rake::RDocTask.new :dev_rdoc do |rd|
|
49
|
-
rd.rdoc_dir = '../../../www/trunk/dev/html/Tools/ar_mailer'
|
50
|
-
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
51
|
-
rd.main = 'README'
|
52
|
-
rd.options << '-d' if `which dot` =~ /\/dot/
|
53
|
-
rd.options << '-t ar_mailer'
|
54
|
-
end
|
55
|
-
|
56
|
-
desc 'Build Gem'
|
57
|
-
Rake::GemPackageTask.new spec do |pkg|
|
58
|
-
pkg.need_tar = true
|
59
|
-
end
|
60
|
-
|
61
|
-
desc 'Clean up'
|
62
|
-
task :clean => [ :clobber_rdoc, :clobber_package ]
|
63
|
-
|
64
|
-
desc 'Clean up'
|
65
|
-
task :clobber => [ :clean ]
|
66
|
-
|
67
|
-
# vim: syntax=Ruby
|
@@ -7,26 +7,26 @@ require 'action_mailer'
|
|
7
7
|
# == Converting to ActionMailer::ARMailer
|
8
8
|
#
|
9
9
|
# Go to your Rails project:
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# $ cd your_rails_project
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# Create a new migration:
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# $ ar_sendmail --create-migration
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# You'll need to redirect this into a file. If you want a different name
|
18
18
|
# provide the --table-name option.
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# Create a new model:
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# $ ar_sendmail --create-model
|
23
|
-
#
|
23
|
+
#
|
24
24
|
# You'll need to redirect this into a file. If you want a different name
|
25
25
|
# provide the --table-name option.
|
26
|
-
#
|
26
|
+
#
|
27
27
|
# Change your email classes to inherit from ActionMailer::ARMailer instead of
|
28
28
|
# ActionMailer::Base:
|
29
|
-
#
|
29
|
+
#
|
30
30
|
# --- app/model/emailer.rb.orig 2006-08-10 13:16:33.000000000 -0700
|
31
31
|
# +++ app/model/emailer.rb 2006-08-10 13:16:43.000000000 -0700
|
32
32
|
# @@ -1,4 +1,4 @@
|
@@ -35,31 +35,64 @@ require 'action_mailer'
|
|
35
35
|
#
|
36
36
|
# def comment_notification(comment)
|
37
37
|
# from comment.author.email
|
38
|
-
#
|
38
|
+
#
|
39
|
+
# You'll need to be sure to set the From address for your emails. Something
|
40
|
+
# like:
|
41
|
+
#
|
42
|
+
# def list_send(recipient)
|
43
|
+
# from 'no_reply@example.com'
|
44
|
+
# # ...
|
45
|
+
#
|
46
|
+
# Edit config/environment.rb and require ar_mailer.rb:
|
47
|
+
#
|
48
|
+
# require 'action_mailer/ar_mailer'
|
49
|
+
#
|
39
50
|
# Edit config/environments/production.rb and set the delivery agent:
|
40
|
-
#
|
51
|
+
#
|
41
52
|
# $ grep delivery_method config/environments/production.rb
|
42
53
|
# ActionMailer::Base.delivery_method = :activerecord
|
43
|
-
#
|
54
|
+
#
|
44
55
|
# Run ar_sendmail:
|
45
|
-
#
|
56
|
+
#
|
46
57
|
# $ ar_sendmail
|
47
|
-
#
|
58
|
+
#
|
48
59
|
# You can also run it from cron with -o, or as a daemon with -d.
|
49
60
|
#
|
50
61
|
# See <tt>ar_sendmail -h</tt> for full details.
|
62
|
+
#
|
63
|
+
# == Alternate Mail Storage
|
64
|
+
#
|
65
|
+
# If you want to set the ActiveRecord model that emails will be stored in,
|
66
|
+
# see ActionMailer::ARMailer::email_class=
|
51
67
|
|
52
68
|
class ActionMailer::ARMailer < ActionMailer::Base
|
53
69
|
|
70
|
+
VERSION = '1.2.0' # :nodoc:
|
71
|
+
|
72
|
+
@@email_class = Email
|
73
|
+
|
74
|
+
##
|
75
|
+
# Current email class for deliveries.
|
76
|
+
|
77
|
+
def self.email_class
|
78
|
+
@@email_class
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Sets the email class for deliveries.
|
83
|
+
|
84
|
+
def self.email_class=(klass)
|
85
|
+
@@email_class = klass
|
86
|
+
end
|
87
|
+
|
54
88
|
##
|
55
89
|
# Adds +mail+ to the Email table. Only the first From address for +mail+ is
|
56
90
|
# used.
|
57
91
|
|
58
92
|
def perform_delivery_activerecord(mail)
|
59
93
|
mail.destinations.each do |destination|
|
60
|
-
|
61
|
-
|
62
|
-
:from => mail.from.first
|
94
|
+
@@email_class.create :mail => mail.encoded, :to => destination,
|
95
|
+
:from => mail.from.first
|
63
96
|
end
|
64
97
|
end
|
65
98
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'optparse'
|
2
|
+
require 'net/smtp'
|
3
|
+
require 'smtp_tls'
|
2
4
|
require 'rubygems'
|
3
|
-
require 'action_mailer'
|
4
5
|
|
5
6
|
class Object # :nodoc:
|
6
7
|
unless respond_to? :path2class then
|
@@ -13,7 +14,8 @@ end
|
|
13
14
|
##
|
14
15
|
# Hack in RSET
|
15
16
|
|
16
|
-
|
17
|
+
module Net # :nodoc:
|
18
|
+
class SMTP # :nodoc:
|
17
19
|
|
18
20
|
unless instance_methods.include? 'reset' then
|
19
21
|
##
|
@@ -25,10 +27,18 @@ class Net::SMTP # :nodoc:
|
|
25
27
|
end
|
26
28
|
|
27
29
|
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ActionMailer; end # :nodoc:
|
28
33
|
|
29
34
|
##
|
30
35
|
# ActionMailer::ARSendmail delivers email from the email table to the
|
31
|
-
# configured
|
36
|
+
# SMTP server configured in your application's config/environment.rb.
|
37
|
+
# ar_sendmail does not work with sendmail delivery.
|
38
|
+
#
|
39
|
+
# ar_mailer can deliver to SMTP with TLS using smtp_tls.rb borrowed from Kyle
|
40
|
+
# Maxwell's action_mailer_optional_tls plugin. Simply set the :tls option in
|
41
|
+
# ActionMailer::Base's smtp_settings to true to enable TLS.
|
32
42
|
#
|
33
43
|
# See ar_sendmail -h for the full list of supported options.
|
34
44
|
#
|
@@ -70,6 +80,7 @@ class ActionMailer::ARSendmail
|
|
70
80
|
# Creates a new migration using +table_name+ and prints it on stdout.
|
71
81
|
|
72
82
|
def self.create_migration(table_name)
|
83
|
+
require 'active_support'
|
73
84
|
puts <<-EOF
|
74
85
|
class Add#{table_name.classify} < ActiveRecord::Migration
|
75
86
|
def self.up
|
@@ -78,11 +89,12 @@ class Add#{table_name.classify} < ActiveRecord::Migration
|
|
78
89
|
t.column :to, :string
|
79
90
|
t.column :last_send_attempt, :integer, :default => 0
|
80
91
|
t.column :mail, :text
|
92
|
+
t.column :created_on, :datetime
|
81
93
|
end
|
82
94
|
end
|
83
95
|
|
84
96
|
def self.down
|
85
|
-
drop_table :
|
97
|
+
drop_table :emails
|
86
98
|
end
|
87
99
|
end
|
88
100
|
EOF
|
@@ -92,6 +104,7 @@ end
|
|
92
104
|
# Creates a new model using +table_name+ and prints it on stdout.
|
93
105
|
|
94
106
|
def self.create_model(table_name)
|
107
|
+
require 'active_support'
|
95
108
|
puts <<-EOF
|
96
109
|
class #{table_name.classify} < ActiveRecord::Base
|
97
110
|
end
|
@@ -105,8 +118,9 @@ end
|
|
105
118
|
# known. See http://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html
|
106
119
|
# to learn how to enable ActiveRecord::Timestamp.
|
107
120
|
|
108
|
-
def self.mailq
|
109
|
-
|
121
|
+
def self.mailq(table_name)
|
122
|
+
klass = table_name.split('::').inject(Object) { |k,n| k.const_get n }
|
123
|
+
emails = klass.find :all
|
110
124
|
|
111
125
|
if emails.empty? then
|
112
126
|
puts "Mail queue is empty"
|
@@ -285,7 +299,7 @@ end
|
|
285
299
|
create_model options[:TableName]
|
286
300
|
exit
|
287
301
|
elsif options.include? :MailQ then
|
288
|
-
mailq
|
302
|
+
mailq options[:TableName]
|
289
303
|
exit
|
290
304
|
end
|
291
305
|
|
@@ -296,8 +310,14 @@ end
|
|
296
310
|
|
297
311
|
new(options).run
|
298
312
|
|
299
|
-
rescue
|
313
|
+
rescue SystemExit
|
314
|
+
raise
|
315
|
+
rescue SignalException
|
300
316
|
exit
|
317
|
+
rescue Exception => e
|
318
|
+
$stderr.puts "Unhandled exception #{e.message}(#{e.class}):"
|
319
|
+
$stderr.puts "\t#{e.backtrace.join "\n\t"}"
|
320
|
+
exit 1
|
301
321
|
end
|
302
322
|
|
303
323
|
##
|
@@ -338,10 +358,12 @@ end
|
|
338
358
|
# Delivers +emails+ to ActionMailer's SMTP server and destroys them.
|
339
359
|
|
340
360
|
def deliver(emails)
|
361
|
+
user = server_settings[:user] || server_settings[:user_name]
|
341
362
|
Net::SMTP.start server_settings[:address], server_settings[:port],
|
342
|
-
server_settings[:domain],
|
363
|
+
server_settings[:domain], user,
|
343
364
|
server_settings[:password],
|
344
|
-
server_settings[:authentication]
|
365
|
+
server_settings[:authentication],
|
366
|
+
server_settings[:tls] do |smtp|
|
345
367
|
until emails.empty? do
|
346
368
|
email = emails.shift
|
347
369
|
begin
|
@@ -354,8 +376,11 @@ end
|
|
354
376
|
[email.id, e.message, e.class, e.backtrace.join("\n\t")]
|
355
377
|
email.destroy
|
356
378
|
smtp.reset
|
357
|
-
rescue Net::SMTPServerBusy
|
358
|
-
|
379
|
+
rescue Net::SMTPServerBusy => e
|
380
|
+
log "server too busy, sleeping #{@delay} seconds"
|
381
|
+
sleep delay unless $TESTING
|
382
|
+
return
|
383
|
+
rescue Net::SMTPServerBusy, Net::SMTPUnknownError, Net::SMTPSyntaxError, TimeoutError => e
|
359
384
|
email.last_send_attempt = Time.now.to_i
|
360
385
|
email.save rescue nil
|
361
386
|
log "error sending email %d: %p(%s):\n\t%s" %
|
@@ -364,6 +389,8 @@ end
|
|
364
389
|
end
|
365
390
|
end
|
366
391
|
end
|
392
|
+
rescue Net::SMTPServerBusy, SystemCallError
|
393
|
+
# ignore SMTPServerBusy/EPIPE/ECONNRESET from Net::SMTP.start's ensure
|
367
394
|
end
|
368
395
|
|
369
396
|
##
|
@@ -371,7 +398,7 @@ end
|
|
371
398
|
|
372
399
|
def do_exit
|
373
400
|
log "caught signal, shutting down"
|
374
|
-
|
401
|
+
exit
|
375
402
|
end
|
376
403
|
|
377
404
|
##
|
data/lib/smtp_tls.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Original code believed public domain from ruby-talk or ruby-core email.
|
2
|
+
# Modifications by Kyle Maxwell <kyle@kylemaxwell.com> used under MIT license.
|
3
|
+
|
4
|
+
require "openssl"
|
5
|
+
require "net/smtp"
|
6
|
+
|
7
|
+
# :stopdoc:
|
8
|
+
|
9
|
+
class Net::SMTP
|
10
|
+
|
11
|
+
class << self
|
12
|
+
send :remove_method, :start
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.start( address, port = nil,
|
16
|
+
helo = 'localhost.localdomain',
|
17
|
+
user = nil, secret = nil, authtype = nil, use_tls = false,
|
18
|
+
&block) # :yield: smtp
|
19
|
+
new(address, port).start(helo, user, secret, authtype, use_tls, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias tls_old_start start
|
23
|
+
|
24
|
+
def start( helo = 'localhost.localdomain',
|
25
|
+
user = nil, secret = nil, authtype = nil, use_tls = false ) # :yield: smtp
|
26
|
+
start_method = use_tls ? :do_tls_start : :do_start
|
27
|
+
if block_given?
|
28
|
+
begin
|
29
|
+
send start_method, helo, user, secret, authtype
|
30
|
+
return yield(self)
|
31
|
+
ensure
|
32
|
+
do_finish
|
33
|
+
end
|
34
|
+
else
|
35
|
+
send start_method, helo, user, secret, authtype
|
36
|
+
return self
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def do_tls_start(helodomain, user, secret, authtype)
|
43
|
+
raise IOError, 'SMTP session already started' if @started
|
44
|
+
check_auth_args user, secret, authtype if user or secret
|
45
|
+
|
46
|
+
sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
|
47
|
+
@socket = Net::InternetMessageIO.new(sock)
|
48
|
+
@socket.read_timeout = 60 #@read_timeout
|
49
|
+
@socket.debug_output = STDERR #@debug_output
|
50
|
+
|
51
|
+
check_response(critical { recv_response() })
|
52
|
+
do_helo(helodomain)
|
53
|
+
|
54
|
+
raise 'openssl library not installed' unless defined?(OpenSSL)
|
55
|
+
starttls
|
56
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock)
|
57
|
+
ssl.sync_close = true
|
58
|
+
ssl.connect
|
59
|
+
@socket = Net::InternetMessageIO.new(ssl)
|
60
|
+
@socket.read_timeout = 60 #@read_timeout
|
61
|
+
@socket.debug_output = STDERR #@debug_output
|
62
|
+
do_helo(helodomain)
|
63
|
+
|
64
|
+
authenticate user, secret, authtype if user
|
65
|
+
@started = true
|
66
|
+
ensure
|
67
|
+
unless @started
|
68
|
+
# authentication failed, cancel connection.
|
69
|
+
@socket.close if not @started and @socket and not @socket.closed?
|
70
|
+
@socket = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def do_helo(helodomain)
|
75
|
+
begin
|
76
|
+
if @esmtp
|
77
|
+
ehlo helodomain
|
78
|
+
else
|
79
|
+
helo helodomain
|
80
|
+
end
|
81
|
+
rescue Net::ProtocolError
|
82
|
+
if @esmtp
|
83
|
+
@esmtp = false
|
84
|
+
@error_occured = false
|
85
|
+
retry
|
86
|
+
end
|
87
|
+
raise
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def starttls
|
92
|
+
getok('STARTTLS')
|
93
|
+
end
|
94
|
+
|
95
|
+
alias tls_old_quit quit
|
96
|
+
|
97
|
+
def quit
|
98
|
+
begin
|
99
|
+
getok('QUIT')
|
100
|
+
rescue EOFError
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end unless Net::SMTP.private_method_defined? :do_tls_start or
|
105
|
+
Net::SMTP.method_defined? :tls?
|
data/test/action_mailer.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'net/smtp'
|
2
|
+
require 'smtp_tls'
|
2
3
|
require 'time'
|
3
4
|
|
4
5
|
class Net::SMTP
|
@@ -15,7 +16,7 @@ class Net::SMTP
|
|
15
16
|
attr_reader :send_message_block
|
16
17
|
attr_accessor :reset_called
|
17
18
|
|
18
|
-
|
19
|
+
send :remove_method, :start
|
19
20
|
|
20
21
|
end
|
21
22
|
|
@@ -33,13 +34,13 @@ class Net::SMTP
|
|
33
34
|
@reset_called = 0
|
34
35
|
end
|
35
36
|
|
36
|
-
alias
|
37
|
+
alias test_old_reset reset if instance_methods.include? 'reset'
|
37
38
|
|
38
39
|
def reset
|
39
40
|
self.class.reset_called += 1
|
40
41
|
end
|
41
42
|
|
42
|
-
alias
|
43
|
+
alias test_old_send_message send_message
|
43
44
|
|
44
45
|
def send_message(mail, to, from)
|
45
46
|
return self.class.send_message_block.call(mail, to, from) unless
|
@@ -94,7 +95,7 @@ end
|
|
94
95
|
|
95
96
|
class Email
|
96
97
|
|
97
|
-
START = Time.parse 'Thu Aug 10 11:19:48'
|
98
|
+
START = Time.parse 'Thu Aug 10 2006 11:19:48'
|
98
99
|
|
99
100
|
attr_accessor :from, :to, :mail, :last_send_attempt, :created_on, :id
|
100
101
|
|
@@ -145,6 +146,8 @@ class Email
|
|
145
146
|
|
146
147
|
end
|
147
148
|
|
149
|
+
Mail = Email
|
150
|
+
|
148
151
|
class String
|
149
152
|
def classify
|
150
153
|
self
|
data/test/test_armailer.rb
CHANGED
@@ -19,7 +19,18 @@ end
|
|
19
19
|
class TestARMailer < Test::Unit::TestCase
|
20
20
|
|
21
21
|
def setup
|
22
|
+
Mailer.email_class = Email
|
23
|
+
|
22
24
|
Email.records.clear
|
25
|
+
Mail.records.clear
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_self_email_class_equals
|
29
|
+
Mailer.email_class = Mail
|
30
|
+
|
31
|
+
Mailer.deliver_mail
|
32
|
+
|
33
|
+
assert_equal 2, Mail.records.length
|
23
34
|
end
|
24
35
|
|
25
36
|
def test_perform_delivery_activerecord
|
data/test/test_arsendmail.rb
CHANGED
@@ -4,6 +4,8 @@ require 'action_mailer/ar_sendmail'
|
|
4
4
|
require 'rubygems'
|
5
5
|
require 'test/zentest_assertions'
|
6
6
|
|
7
|
+
$TESTING = true
|
8
|
+
|
7
9
|
class TestARSendmail < Test::Unit::TestCase
|
8
10
|
|
9
11
|
def setup
|
@@ -23,31 +25,6 @@ class TestARSendmail < Test::Unit::TestCase
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def test_class_create_migration
|
26
|
-
out, = util_capture do
|
27
|
-
ActionMailer::ARSendmail.create_migration 'Email'
|
28
|
-
end
|
29
|
-
|
30
|
-
expected = <<-EOF
|
31
|
-
class AddEmail < ActiveRecord::Migration
|
32
|
-
def self.up
|
33
|
-
create_table :email do |t|
|
34
|
-
t.column :from, :string
|
35
|
-
t.column :to, :string
|
36
|
-
t.column :last_send_attempt, :integer, :default => 0
|
37
|
-
t.column :mail, :text
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.down
|
42
|
-
drop_table :email
|
43
|
-
end
|
44
|
-
end
|
45
|
-
EOF
|
46
|
-
|
47
|
-
assert_equal expected, out.string
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_class_create_migration_table_name
|
51
28
|
out, = util_capture do
|
52
29
|
ActionMailer::ARSendmail.create_migration 'Mail'
|
53
30
|
end
|
@@ -60,11 +37,12 @@ class AddMail < ActiveRecord::Migration
|
|
60
37
|
t.column :to, :string
|
61
38
|
t.column :last_send_attempt, :integer, :default => 0
|
62
39
|
t.column :mail, :text
|
40
|
+
t.column :created_on, :datetime
|
63
41
|
end
|
64
42
|
end
|
65
43
|
|
66
44
|
def self.down
|
67
|
-
drop_table :
|
45
|
+
drop_table :emails
|
68
46
|
end
|
69
47
|
end
|
70
48
|
EOF
|
@@ -73,19 +51,6 @@ end
|
|
73
51
|
end
|
74
52
|
|
75
53
|
def test_class_create_model
|
76
|
-
out, = util_capture do
|
77
|
-
ActionMailer::ARSendmail.create_model 'Email'
|
78
|
-
end
|
79
|
-
|
80
|
-
expected = <<-EOF
|
81
|
-
class Email < ActiveRecord::Base
|
82
|
-
end
|
83
|
-
EOF
|
84
|
-
|
85
|
-
assert_equal expected, out.string
|
86
|
-
end
|
87
|
-
|
88
|
-
def test_class_create_model_table_name
|
89
54
|
out, = util_capture do
|
90
55
|
ActionMailer::ARSendmail.create_model 'Mail'
|
91
56
|
end
|
@@ -106,10 +71,10 @@ end
|
|
106
71
|
last = Email.create :from => nobody, :to => 'recip@h2.example.com',
|
107
72
|
:mail => 'body2'
|
108
73
|
|
109
|
-
last.last_send_attempt = Time.parse('Thu Aug 10 11:40:05').to_i
|
74
|
+
last.last_send_attempt = Time.parse('Thu Aug 10 2006 11:40:05').to_i
|
110
75
|
|
111
76
|
out, err = util_capture do
|
112
|
-
ActionMailer::ARSendmail.mailq
|
77
|
+
ActionMailer::ARSendmail.mailq 'Email'
|
113
78
|
end
|
114
79
|
|
115
80
|
expected = <<-EOF
|
@@ -132,7 +97,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
132
97
|
|
133
98
|
def test_class_mailq_empty
|
134
99
|
out, err = util_capture do
|
135
|
-
ActionMailer::ARSendmail.mailq
|
100
|
+
ActionMailer::ARSendmail.mailq 'Email'
|
136
101
|
end
|
137
102
|
|
138
103
|
assert_equal "Mail queue is empty\n", out.string
|
@@ -232,7 +197,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
232
197
|
|
233
198
|
def test_class_parse_args_mailq
|
234
199
|
options = ActionMailer::ARSendmail.process_args []
|
235
|
-
deny_includes
|
200
|
+
deny_includes :MailQ, options
|
236
201
|
|
237
202
|
argv = %w[--mailq]
|
238
203
|
|
@@ -243,7 +208,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
243
208
|
|
244
209
|
def test_class_parse_args_migration
|
245
210
|
options = ActionMailer::ARSendmail.process_args []
|
246
|
-
deny_includes
|
211
|
+
deny_includes :Migration, options
|
247
212
|
|
248
213
|
argv = %w[--create-migration]
|
249
214
|
|
@@ -254,7 +219,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
254
219
|
|
255
220
|
def test_class_parse_args_model
|
256
221
|
options = ActionMailer::ARSendmail.process_args []
|
257
|
-
deny_includes
|
222
|
+
deny_includes :Model, options
|
258
223
|
|
259
224
|
argv = %w[--create-model]
|
260
225
|
|
@@ -371,7 +336,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
371
336
|
|
372
337
|
def test_deliver_4xx_error
|
373
338
|
Net::SMTP.on_send_message do
|
374
|
-
e = Net::
|
339
|
+
e = Net::SMTPSyntaxError.new 'try again'
|
375
340
|
e.set_backtrace %w[one two three]
|
376
341
|
raise e
|
377
342
|
end
|
@@ -390,7 +355,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
390
355
|
assert_equal 1, Net::SMTP.reset_called, 'Reset connection on SyntaxError'
|
391
356
|
|
392
357
|
assert_equal '', out.string
|
393
|
-
assert_equal "error sending email 1: \"try again\"(Net::
|
358
|
+
assert_equal "error sending email 1: \"try again\"(Net::SMTPSyntaxError):\n\tone\n\ttwo\n\tthree\n", err.string
|
394
359
|
end
|
395
360
|
|
396
361
|
def test_deliver_5xx_error
|
@@ -416,6 +381,52 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
416
381
|
assert_equal "5xx error sending email 1, removing from queue: \"unknown recipient\"(Net::SMTPFatalError):\n\tone\n\ttwo\n\tthree\n", err.string
|
417
382
|
end
|
418
383
|
|
384
|
+
def test_deliver_errno_epipe
|
385
|
+
Net::SMTP.on_send_message do
|
386
|
+
raise Errno::EPIPE
|
387
|
+
end
|
388
|
+
|
389
|
+
now = Time.now.to_i
|
390
|
+
|
391
|
+
email = Email.create :mail => 'body', :to => 'to', :from => 'from'
|
392
|
+
|
393
|
+
out, err = util_capture do
|
394
|
+
@sm.deliver [email]
|
395
|
+
end
|
396
|
+
|
397
|
+
assert_equal 0, Net::SMTP.deliveries.length
|
398
|
+
assert_equal 1, Email.records.length
|
399
|
+
assert_operator now, :>=, Email.records.first.last_send_attempt
|
400
|
+
assert_equal 0, Net::SMTP.reset_called, 'Reset connection on SyntaxError'
|
401
|
+
|
402
|
+
assert_equal '', out.string
|
403
|
+
assert_equal '', err.string
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_deliver_server_busy
|
407
|
+
Net::SMTP.on_send_message do
|
408
|
+
e = Net::SMTPServerBusy.new 'try again'
|
409
|
+
e.set_backtrace %w[one two three]
|
410
|
+
raise e
|
411
|
+
end
|
412
|
+
|
413
|
+
now = Time.now.to_i
|
414
|
+
|
415
|
+
email = Email.create :mail => 'body', :to => 'to', :from => 'from'
|
416
|
+
|
417
|
+
out, err = util_capture do
|
418
|
+
@sm.deliver [email]
|
419
|
+
end
|
420
|
+
|
421
|
+
assert_equal 0, Net::SMTP.deliveries.length
|
422
|
+
assert_equal 1, Email.records.length
|
423
|
+
assert_operator now, :>=, Email.records.first.last_send_attempt
|
424
|
+
assert_equal 0, Net::SMTP.reset_called, 'Reset connection on SyntaxError'
|
425
|
+
|
426
|
+
assert_equal '', out.string
|
427
|
+
assert_equal "server too busy, sleeping 60 seconds\n", err.string
|
428
|
+
end
|
429
|
+
|
419
430
|
def test_deliver_syntax_error
|
420
431
|
Net::SMTP.on_send_message do
|
421
432
|
Net::SMTP.on_send_message # clear
|
@@ -433,7 +444,7 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
433
444
|
@sm.deliver [email1, email2]
|
434
445
|
end
|
435
446
|
|
436
|
-
assert_equal 1, Net::SMTP.deliveries.length
|
447
|
+
assert_equal 1, Net::SMTP.deliveries.length, 'delivery count'
|
437
448
|
assert_equal 1, Email.records.length
|
438
449
|
assert_equal 1, Net::SMTP.reset_called, 'Reset connection on SyntaxError'
|
439
450
|
assert_operator now, :<=, Email.records.first.last_send_attempt
|
@@ -442,9 +453,33 @@ Last send attempt: Thu Aug 10 11:40:05 -0700 2006
|
|
442
453
|
assert_equal "error sending email 1: \"blah blah blah\"(Net::SMTPSyntaxError):\n\tone\n\ttwo\n\tthree\nsent email 00000000002 from from to to: \"queued\"\n", err.string
|
443
454
|
end
|
444
455
|
|
456
|
+
def test_deliver_timeout
|
457
|
+
Net::SMTP.on_send_message do
|
458
|
+
e = Timeout::Error.new 'timed out'
|
459
|
+
e.set_backtrace %w[one two three]
|
460
|
+
raise e
|
461
|
+
end
|
462
|
+
|
463
|
+
now = Time.now.to_i
|
464
|
+
|
465
|
+
email = Email.create :mail => 'body', :to => 'to', :from => 'from'
|
466
|
+
|
467
|
+
out, err = util_capture do
|
468
|
+
@sm.deliver [email]
|
469
|
+
end
|
470
|
+
|
471
|
+
assert_equal 0, Net::SMTP.deliveries.length
|
472
|
+
assert_equal 1, Email.records.length
|
473
|
+
assert_operator now, :>=, Email.records.first.last_send_attempt
|
474
|
+
assert_equal 1, Net::SMTP.reset_called, 'Reset connection on Timeout'
|
475
|
+
|
476
|
+
assert_equal '', out.string
|
477
|
+
assert_equal "error sending email 1: \"timed out\"(Timeout::Error):\n\tone\n\ttwo\n\tthree\n", err.string
|
478
|
+
end
|
479
|
+
|
445
480
|
def test_do_exit
|
446
481
|
out, err = util_capture do
|
447
|
-
assert_raise
|
482
|
+
assert_raise SystemExit do
|
448
483
|
@sm.do_exit
|
449
484
|
end
|
450
485
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.
|
2
|
+
rubygems_version: 0.9.4
|
3
3
|
specification_version: 1
|
4
4
|
name: ar_mailer
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date:
|
8
|
-
summary: A two-phase
|
6
|
+
version: 1.2.0
|
7
|
+
date: 2007-06-05 00:00:00 -07:00
|
8
|
+
summary: A two-phase delivery agent for ActionMailer
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
|
-
email:
|
12
|
-
homepage:
|
13
|
-
rubyforge_project:
|
14
|
-
description:
|
11
|
+
email: drbrain@segment7.net
|
12
|
+
homepage: http://seattlerb.org/ar_mailer
|
13
|
+
rubyforge_project: seattlerb
|
14
|
+
description: Even deliviring email to the local machine may take too long when you have to send hundreds of messages. ar_mailer allows you to store messages into the database for later delivery by a separate process, ar_sendmail.
|
15
15
|
autorequire:
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|
@@ -29,28 +29,43 @@ post_install_message:
|
|
29
29
|
authors:
|
30
30
|
- Eric Hodel
|
31
31
|
files:
|
32
|
-
-
|
32
|
+
- History.txt
|
33
|
+
- LICENSE.txt
|
33
34
|
- Manifest.txt
|
34
|
-
- README
|
35
|
+
- README.txt
|
35
36
|
- Rakefile
|
36
37
|
- bin/ar_sendmail
|
37
38
|
- lib/action_mailer/ar_mailer.rb
|
38
39
|
- lib/action_mailer/ar_sendmail.rb
|
40
|
+
- lib/smtp_tls.rb
|
39
41
|
- share/ar_sendmail
|
40
42
|
- test/action_mailer.rb
|
41
43
|
- test/test_armailer.rb
|
42
44
|
- test/test_arsendmail.rb
|
43
|
-
test_files:
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
test_files:
|
46
|
+
- test/test_armailer.rb
|
47
|
+
- test/test_arsendmail.rb
|
48
|
+
rdoc_options:
|
49
|
+
- --main
|
50
|
+
- README.txt
|
51
|
+
extra_rdoc_files:
|
52
|
+
- History.txt
|
53
|
+
- LICENSE.txt
|
54
|
+
- Manifest.txt
|
55
|
+
- README.txt
|
49
56
|
executables:
|
50
57
|
- ar_sendmail
|
51
58
|
extensions: []
|
52
59
|
|
53
60
|
requirements: []
|
54
61
|
|
55
|
-
dependencies:
|
56
|
-
|
62
|
+
dependencies:
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: hoe
|
65
|
+
version_requirement:
|
66
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.2.1
|
71
|
+
version:
|