ar_mailer_rails3 2.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ test
2
+ pkg
3
+ .DS_Store
data/History.txt ADDED
@@ -0,0 +1,158 @@
1
+ = 2.1.8
2
+
3
+ * Bugs fixed
4
+ * Fix BCC addresses being visible to all recipients (laserlemon)
5
+
6
+ = 2.1.7
7
+
8
+ * Miscellaneous Updates
9
+ * Added adzap-ar_mailer file to end the need for the config.gem :lib option
10
+
11
+ * Bugs fixed
12
+ * Fix from address being set as address header object.
13
+
14
+ = 2.1.6
15
+
16
+ * Miscellaneous Updates
17
+ * Use return-path as from address if set, as per default ActionMailer::Base SMTP delivery (Dustin Tinney)
18
+ * Always wait full delay between deliveries (cyu)
19
+
20
+ * Bugs fixed
21
+ * Non-zero return code returned in init.d script (hennk)
22
+ * Use updated Timeout error class (hennk)
23
+
24
+ = 2.1.5
25
+
26
+ * Bugs fixed
27
+ * Load ar_mailer after environment to fix issue with lazy loading of ActionMailer in Rails 2.3
28
+
29
+ = 2.1.4
30
+
31
+ * Bugs fixed
32
+ * Explicitly require ar_mailer in ar_sendmail because its not getting loaded by the Rails environment for some reason
33
+
34
+ = 2.1.3
35
+
36
+ * Tests now pass on gem install
37
+ * Removed deprecated ActionMailer::ARMailer class
38
+ * Bugs fixed
39
+ * Fixed issue with pre-loading ActionMailer. No use ActionMailer::Base.email_class directly rather than store in ARSendmail instance var so no need to pre-load ActionMailer.
40
+
41
+ = 2.1.2
42
+
43
+ * Bugs fixed
44
+ * Require ar_mailer in ar_sendmail since the change to remove TableName and use email_class
45
+
46
+ = 2.1.1
47
+
48
+ * Force gem rebuild
49
+
50
+ = 2.1.0
51
+
52
+ * Switched to using a Rails generator for migration and model files. The ar_sendmail options have been removed.
53
+
54
+ = 2.0.2
55
+
56
+ * Removed TableName option from ar_sendmail options as its redundant. The Rails environment gets loaded so the settings for email class also get loaded
57
+ * Bugs fixed
58
+ * Email class reloading issue in development mode causing AR email class defaults to be lost when cached
59
+
60
+ = 2.0.1
61
+
62
+ * Added option to use smtp setting of :tls => false to disable TLS auto start in Ruby 1.8.7+
63
+ * Removed some cruft which can be handled by ActiveSupport
64
+
65
+ = 2.0.0
66
+
67
+ * Removed need to use ARMailer subclass. Just set the delivery method and you are ready to go. Backwards compatible with a deprecation notice if you subclass old ARMailer class.
68
+ * Only include SMTP TLS patch if Ruby version < 1.8.7 as it has an alternative. Changes based on Calvin Yu's [cyu] fork.
69
+ * Renamed default migration name to the modern Rails default
70
+ * Only authenticate if emails waiting to be sent
71
+ * Added --version switch to ar_sendmail binary
72
+ * Created a lighthouse account for this project (adzap fork only). See README.
73
+
74
+ = 1.4.4
75
+
76
+ * Exit init.d script with message if no mailers defined.
77
+
78
+ = 1.4.3
79
+
80
+ * Bugs fixed
81
+ * Replaced mistaken call to log when removing pid file artifact for
82
+ non-running daemon
83
+
84
+ = 1.4.2
85
+
86
+ * New Features
87
+ * Added Ruby based linux init.d script for handling daemon startup using yaml
88
+ config file. See files share/linux/ar_sendmail and ar_sendmail.conf
89
+ * Bugs fixed
90
+ * Proper handling for relative and absolute paths for the pid file
91
+ * Removed hoe dependency since we need the explicit gemspec file for github and
92
+ not deploying to RubyForge its not as useful.
93
+ * Moved old BSD rc.d script to share/bsd folder
94
+ * Updated README with github gem install, docs and init script info
95
+
96
+ = 1.4.1
97
+
98
+ * Bugs fixed
99
+ * Daemon failed on startup fixed with expanding full path of pid file
100
+
101
+ = 1.4.0
102
+
103
+ * Forked gem and published on GitHub (gem sources -a http://gems.github.com)
104
+ * New Features
105
+ * Added pid file creation on daemonize with command line option to specify pid filename [Dylan Egan]
106
+
107
+ = 1.3.1
108
+
109
+ * Fix bug #12530, gmail causes SSL errors. Submitted by Kyle Maxwell
110
+ and Alex Ostleitner.
111
+ * Try ActionMailer::Base::server_settings then ::smtp_settings. Fixes
112
+ bug #12516. Submitted by Alex Ostleitner.
113
+
114
+ = 1.3.0
115
+
116
+ * New Features
117
+ * Added automatic mail queue cleanup.
118
+ * MAY CAUSE LOSS OF DATA. If you haven't run ar_sendmail within
119
+ the expiry time, set it to 0.
120
+ * Bugs fixed
121
+ * Authentication errors are now handled by retrying once.
122
+
123
+ = 1.2.0
124
+
125
+ * Bugs fixed
126
+ * Handle SMTPServerBusy by backing off @delay seconds then re-queueing
127
+ * Allow email delivery class to be set in ARMailer.
128
+ * ar_sendmail --mailq works with --table-name now.
129
+ * Miscellaneous Updates
130
+ * Added documentation to require 'action_mailer/ar_mailer' in
131
+ instructions.
132
+ * Moved to ZSS p4 repository
133
+ * Supports TLS now. Requested by Dave Thomas. smtp_tls.rb from Kyle
134
+ Maxwell & etc.
135
+
136
+ = 1.1.0
137
+
138
+ * Features
139
+ * Added --chdir to set rails directory
140
+ * Added --environment to set RAILS_ENV
141
+ * Exits cleanly on TERM or INT signals
142
+ * Added FreeBSD rc.d script
143
+ * Exceptions during SMTP sending are now logged
144
+ * No longer waits if sending email took too long
145
+ * Bugs fixed
146
+ * Fixed last send attempt in --mailq
147
+ * Better SMTP error handling
148
+ * Messages are removed from the queue on 5xx errors
149
+ * Added Net::SMTP.reset to avoid needing to recreate the connection
150
+
151
+ = 1.0.1
152
+
153
+ * Bugs fixed
154
+ * From and to of email destination were swapped
155
+
156
+ = 1.0.0
157
+
158
+ * Birthday
data/LICENSE.txt ADDED
@@ -0,0 +1,28 @@
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.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions
7
+ are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+ 3. Neither the names of the authors nor the names of their contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
19
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
22
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.rdoc ADDED
@@ -0,0 +1,124 @@
1
+ = ar_mailer_rails3
2
+
3
+ A two-phase delivery agent for ActionMailer which works for Rails 3.
4
+
5
+ Forked from http://github.com/adzap/ar_mailer/wikis
6
+
7
+ Rubyforge Project:
8
+
9
+ http://rubyforge.org/projects/seattlerb
10
+
11
+ Documentation:
12
+
13
+ http://seattlerb.org/ar_mailer
14
+
15
+ and for forked additions
16
+
17
+ http://github.com/adzap/ar_mailer_rails3/wikis
18
+
19
+ Bugs:
20
+
21
+ http://adzap.lighthouseapp.com/projects/26997-ar_mailer
22
+
23
+ == About
24
+
25
+ Even delivering email to the local machine may take too long when you have to
26
+ send hundreds of messages. ar_mailer allows you to store messages into the
27
+ database for later delivery by a separate process, ar_sendmail.
28
+
29
+ == Installing ar_mailer_rails3
30
+
31
+ Don't need remove adzap-ar_mailer or ar_mailer, just install ar_mailer_rails3
32
+
33
+ $ sudo gem install ar_mailer_rails3
34
+
35
+ == Usage
36
+
37
+ Go to your Rails project:
38
+
39
+ $ cd your_rails_project
40
+
41
+ Create the migration, model and initializer:
42
+
43
+ This shows the options which are only the model name, which defaults to Email
44
+
45
+ ./script/generate ar_mailer_rails3 -h
46
+
47
+ Then run with defaults
48
+
49
+ ./script/generate ar_mailer email
50
+
51
+ Or specify a custom model name
52
+
53
+ ./script/generate ar_mailer newsletter
54
+
55
+ See Alternate Mail Storage if you use a custom model name
56
+
57
+ In your mailer class methods you must be sure to set the From address for your emails.
58
+ Something like:
59
+
60
+ def list_send(recipient)
61
+ from 'no_reply@example.com'
62
+ # ...
63
+
64
+ Edit config/initializer/ar_mailer_rails3.rb and uncomment below line to use ar_mailer as
65
+ default delivery method:
66
+
67
+ ActionMailer::Base.delivery_method = :active_record
68
+
69
+ Or if you need to, you can set each mailer class delivery method individually:
70
+
71
+ class MyMailer < ActionMailer::Base
72
+ self.delivery_method = :active_record
73
+ end
74
+
75
+ This can be useful when using plugins like ExceptionNotification. Where it
76
+ might be foolish to tie the sending of the email alert to the database when the
77
+ database might be causing the exception being raised. In this instance you could
78
+ override ExceptionNofitier delivery method to be smtp or set the other
79
+ mailer classes to use ARMailer explicitly.
80
+
81
+ Then to run it:
82
+
83
+ $ ar_sendmail_rails3
84
+
85
+ You can also run it from cron with -o, or as a daemon with -d.
86
+
87
+ See <tt>ar_sendmail_rails3 -h</tt> for full details.
88
+
89
+ === Alternate Mail Storage
90
+
91
+ By default ar_mailer_rails3 assumes you are using an ActiveRecord model called
92
+ Email to store the emails created before sending. If you want to change
93
+ this you alter it in an intializer like so:
94
+
95
+ ActionMailer::Base.add_delivery_method :active_record, ArMailer::ActiveRecord, :email_class => Newsletter
96
+
97
+ === A Word on TLS
98
+
99
+ If you are using Ruby >= 1.8.7, TLS will be enabled automatically if your
100
+ SMTP server supports it. If you do not want it to automatically enabled then
101
+ set the :tls option to false in your smtp_settings.
102
+
103
+ If you are on Ruby <= 1.8.6, then the TLS patch included in this plugin will
104
+ be loaded, so you don't need another TLS plugin to add the capability. This
105
+ patch allows you to explicit set if the server supports TLS by setting the
106
+ :tls option to true in your smtp_settings.
107
+
108
+ === Help
109
+
110
+ See ar_sendmail_rails3 -h for options to ar_sendmail_rails3.
111
+
112
+ NOTE: You may need to delete an smtp_tls.rb file if you have one lying
113
+ around. ar_mailer supplies it own.
114
+
115
+ == Run as a service (init.d/rc.d scripts)
116
+
117
+ For Linux both script and demo config files are in share/linux.
118
+ See ar_sendmail.conf for setting up your config. Copy the ar_sendmail file
119
+ to /etc/init.d/ and make it executable. Then for Debian based distros run
120
+ 'sudo update-rc.d ar_sendmail defaults' and it should work. Make sure you have
121
+ the config file /etc/ar_sendmail.conf in place before starting.
122
+
123
+ For FreeBSD or NetBSD script is share/bsd/ar_sendmail. This is old and does not
124
+ support the config file unless someone wants to submit a patch.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |s|
7
+ s.name = "ar_mailer_rails3"
8
+ s.summary = "ArMailer wrapper for Rails 3"
9
+ s.email = "zhangyuanyi@gmail.com"
10
+ s.homepage = "http://github.com/yzhang/ar_mailer_rails3"
11
+ s.description = "ArMailer wrapper for Rails 3"
12
+ s.authors = ["Yuanyi Zhang"]
13
+ s.files = FileList["[A-Z]*", "bin/*", "share/*", "test/*", "{lib}/**/*", '.gitignore']
14
+ s.test_files = []
15
+ end
16
+ rescue LoadError
17
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.1.8
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ar_mailer_rails3/ar_sendmail'
4
+
5
+ ArMailerRails3::ARSendmail.run
6
+
@@ -0,0 +1 @@
1
+ require 'ar_mailer_rails3/active_record'
@@ -0,0 +1,53 @@
1
+ module ArMailerRails3
2
+ # A delivery method implementation which sends via sendmail.
3
+ #
4
+ # To use this, first find out where the sendmail binary is on your computer,
5
+ # if you are on a mac or unix box, it is usually in /usr/sbin/sendmail, this will
6
+ # be your sendmail location.
7
+ #
8
+ # Mail.defaults do
9
+ # delivery_method :sendmail
10
+ # end
11
+ #
12
+ # Or if your sendmail binary is not at '/usr/sbin/sendmail'
13
+ #
14
+ # Mail.defaults do
15
+ # delivery_method :sendmail, :location => '/absolute/path/to/your/sendmail'
16
+ # end
17
+ #
18
+ # Then just deliver the email as normal:
19
+ #
20
+ # Mail.deliver do
21
+ # to 'mikel@test.lindsaar.net'
22
+ # from 'ada@test.lindsaar.net'
23
+ # subject 'testing sendmail'
24
+ # body 'testing sendmail'
25
+ # end
26
+ #
27
+ # Or by calling deliver on a Mail message
28
+ #
29
+ # mail = Mail.new do
30
+ # to 'mikel@test.lindsaar.net'
31
+ # from 'ada@test.lindsaar.net'
32
+ # subject 'testing sendmail'
33
+ # body 'testing sendmail'
34
+ # end
35
+ #
36
+ # mail.deliver!
37
+ class ActiveRecord
38
+
39
+ def initialize(options)
40
+ self.email_class = options[:email_class] || Email
41
+ end
42
+
43
+ attr_accessor :email_class_name, :email_class
44
+
45
+ def deliver!(mail)
46
+ destinations = mail.destinations
47
+ sender = mail.return_path || mail.sender || mail.from_addrs.first
48
+ destinations.each do |destination|
49
+ self.email_class.create :mail => mail.encoded, :to => destination, :from => sender
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,489 @@
1
+ require 'optparse'
2
+ require 'net/smtp'
3
+ require 'smtp_tls' unless Net::SMTP.instance_methods.include?("enable_starttls_auto")
4
+
5
+ ##
6
+ # Hack in RSET
7
+
8
+ module Net # :nodoc:
9
+ class SMTP # :nodoc:
10
+
11
+ unless instance_methods.include? 'reset' then
12
+ ##
13
+ # Resets the SMTP connection.
14
+
15
+ def reset
16
+ getok 'RSET'
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+
23
+ ##
24
+ # ActionMailer::ARSendmail delivers email from the email table to the
25
+ # SMTP server configured in your application's config/environment.rb.
26
+ # ar_sendmail does not work with sendmail delivery.
27
+ #
28
+ # ar_mailer can deliver to SMTP with TLS using smtp_tls.rb borrowed from Kyle
29
+ # Maxwell's action_mailer_optional_tls plugin. Simply set the :tls option in
30
+ # ActionMailer::Base's smtp_settings to true to enable TLS.
31
+ #
32
+ # See ar_sendmail -h for the full list of supported options.
33
+ #
34
+ # The interesting options are:
35
+ # * --daemon
36
+ # * --mailq
37
+
38
+ module ArMailerRails3; end
39
+
40
+ class ArMailerRails3::ARSendmail
41
+
42
+ ##
43
+ # The version of ActionMailer::ARSendmail you are running.
44
+
45
+ VERSION = '2.1.8'
46
+
47
+ ##
48
+ # Maximum number of times authentication will be consecutively retried
49
+
50
+ MAX_AUTH_FAILURES = 2
51
+
52
+ ##
53
+ # Email delivery attempts per run
54
+
55
+ attr_accessor :batch_size
56
+
57
+ ##
58
+ # Seconds to delay between runs
59
+
60
+ attr_accessor :delay
61
+
62
+ ##
63
+ # Maximum age of emails in seconds before they are removed from the queue.
64
+
65
+ attr_accessor :max_age
66
+
67
+ ##
68
+ # Be verbose
69
+
70
+ attr_accessor :verbose
71
+
72
+
73
+ ##
74
+ # True if only one delivery attempt will be made per call to run
75
+
76
+ attr_reader :once
77
+
78
+ ##
79
+ # Times authentication has failed
80
+
81
+ attr_accessor :failed_auth_count
82
+
83
+ @@pid_file = nil
84
+
85
+ def self.remove_pid_file
86
+ if @@pid_file
87
+ require 'shell'
88
+ sh = Shell.new
89
+ sh.rm @@pid_file
90
+ end
91
+ end
92
+
93
+ ##
94
+ # Get email class
95
+
96
+ def self.email_class
97
+ ActionMailer::Base.active_record_settings[:email_class]
98
+ end
99
+
100
+ ##
101
+ # Prints a list of unsent emails and the last delivery attempt, if any.
102
+ #
103
+ # If ActiveRecord::Timestamp is not being used the arrival time will not be
104
+ # known. See http://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html
105
+ # to learn how to enable ActiveRecord::Timestamp.
106
+
107
+ def self.mailq
108
+ emails = self.email_class.find :all
109
+
110
+ if emails.empty? then
111
+ puts "Mail queue is empty"
112
+ return
113
+ end
114
+
115
+ total_size = 0
116
+
117
+ puts "-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------"
118
+ emails.each do |email|
119
+ size = email.mail.length
120
+ total_size += size
121
+
122
+ create_timestamp = email.created_on rescue
123
+ email.created_at rescue
124
+ Time.at(email.created_date) rescue # for Robot Co-op
125
+ nil
126
+
127
+ created = if create_timestamp.nil? then
128
+ ' Unknown'
129
+ else
130
+ create_timestamp.strftime '%a %b %d %H:%M:%S'
131
+ end
132
+
133
+ puts "%10d %8d %s %s" % [email.id, size, created, email.from]
134
+ if email.last_send_attempt > 0 then
135
+ puts "Last send attempt: #{Time.at email.last_send_attempt}"
136
+ end
137
+ puts " #{email.to}"
138
+ puts
139
+ end
140
+
141
+ puts "-- #{total_size/1024} Kbytes in #{emails.length} Requests."
142
+ end
143
+
144
+ ##
145
+ # Processes command line options in +args+
146
+
147
+ def self.process_args(args)
148
+ name = File.basename $0
149
+
150
+ options = {}
151
+ options[:Chdir] = '.'
152
+ options[:Daemon] = false
153
+ options[:Delay] = 60
154
+ options[:MaxAge] = 86400 * 7
155
+ options[:Once] = false
156
+ options[:RailsEnv] = ENV['RAILS_ENV']
157
+ options[:Pidfile] = options[:Chdir] + '/log/ar_sendmail.pid'
158
+
159
+ opts = OptionParser.new do |opts|
160
+ opts.banner = "Usage: #{name} [options]"
161
+ opts.separator ''
162
+
163
+ opts.separator "#{name} scans the email table for new messages and sends them to the"
164
+ opts.separator "website's configured SMTP host."
165
+ opts.separator ''
166
+ opts.separator "#{name} must be run from a Rails application's root."
167
+
168
+ opts.separator ''
169
+ opts.separator 'Sendmail options:'
170
+
171
+ opts.on("-b", "--batch-size BATCH_SIZE",
172
+ "Maximum number of emails to send per delay",
173
+ "Default: Deliver all available emails", Integer) do |batch_size|
174
+ options[:BatchSize] = batch_size
175
+ end
176
+
177
+ opts.on( "--delay DELAY",
178
+ "Delay between checks for new mail",
179
+ "in the database",
180
+ "Default: #{options[:Delay]}", Integer) do |delay|
181
+ options[:Delay] = delay
182
+ end
183
+
184
+ opts.on( "--max-age MAX_AGE",
185
+ "Maxmimum age for an email. After this",
186
+ "it will be removed from the queue.",
187
+ "Set to 0 to disable queue cleanup.",
188
+ "Default: #{options[:MaxAge]} seconds", Integer) do |max_age|
189
+ options[:MaxAge] = max_age
190
+ end
191
+
192
+ opts.on("-o", "--once",
193
+ "Only check for new mail and deliver once",
194
+ "Default: #{options[:Once]}") do |once|
195
+ options[:Once] = once
196
+ end
197
+
198
+ opts.on("-d", "--daemonize",
199
+ "Run as a daemon process",
200
+ "Default: #{options[:Daemon]}") do |daemon|
201
+ options[:Daemon] = true
202
+ end
203
+
204
+ opts.on("-p", "--pidfile PIDFILE",
205
+ "Set the pidfile location",
206
+ "Default: #{options[:Chdir]}#{options[:Pidfile]}", String) do |pidfile|
207
+ options[:Pidfile] = pidfile
208
+ end
209
+
210
+ opts.on( "--mailq",
211
+ "Display a list of emails waiting to be sent") do |mailq|
212
+ options[:MailQ] = true
213
+ end
214
+
215
+ opts.separator ''
216
+ opts.separator 'Setup Options:'
217
+
218
+ opts.separator ''
219
+ opts.separator 'Generic Options:'
220
+
221
+ opts.on("-c", "--chdir PATH",
222
+ "Use PATH for the application path",
223
+ "Default: #{options[:Chdir]}") do |path|
224
+ usage opts, "#{path} is not a directory" unless File.directory? path
225
+ usage opts, "#{path} is not readable" unless File.readable? path
226
+ options[:Chdir] = path
227
+ end
228
+
229
+ opts.on("-e", "--environment RAILS_ENV",
230
+ "Set the RAILS_ENV constant",
231
+ "Default: #{options[:RailsEnv]}") do |env|
232
+ options[:RailsEnv] = env
233
+ end
234
+
235
+ opts.on("-v", "--[no-]verbose",
236
+ "Be verbose",
237
+ "Default: #{options[:Verbose]}") do |verbose|
238
+ options[:Verbose] = verbose
239
+ end
240
+
241
+ opts.on("-h", "--help",
242
+ "You're looking at it") do
243
+ usage opts
244
+ end
245
+
246
+ opts.on("--version", "Version of ARMailer") do
247
+ usage "ar_mailer #{VERSION} (adzap fork)"
248
+ end
249
+
250
+ opts.separator ''
251
+ end
252
+
253
+ opts.parse! args
254
+
255
+ ENV['RAILS_ENV'] = options[:RailsEnv]
256
+
257
+ Dir.chdir options[:Chdir] do
258
+ begin
259
+ require 'config/environment'
260
+ require 'ar_mailer_rails3/active_record'
261
+ rescue LoadError
262
+ usage opts, <<-EOF
263
+ #{name} must be run from a Rails application's root to deliver email.
264
+ #{Dir.pwd} does not appear to be a Rails application root.
265
+ EOF
266
+ end
267
+ end
268
+
269
+ return options
270
+ end
271
+
272
+ ##
273
+ # Processes +args+ and runs as appropriate
274
+
275
+ def self.run(args = ARGV)
276
+ options = process_args args
277
+
278
+ if options.include? :MailQ then
279
+ mailq
280
+ exit
281
+ end
282
+
283
+ if options[:Daemon] then
284
+ require 'webrick/server'
285
+ @@pid_file = File.expand_path(options[:Pidfile], options[:Chdir])
286
+ if File.exists? @@pid_file
287
+ # check to see if process is actually running
288
+ pid = ''
289
+ File.open(@@pid_file, 'r') {|f| pid = f.read.chomp }
290
+ if system("ps -p #{pid} | grep #{pid}") # returns true if process is running, o.w. false
291
+ $stderr.puts "Warning: The pid file #{@@pid_file} exists and ar_sendmail is running. Shutting down."
292
+ exit -1
293
+ else
294
+ # not running, so remove existing pid file and continue
295
+ self.remove_pid_file
296
+ $stderr.puts "ar_sendmail is not running. Removing existing pid file and starting up..."
297
+ end
298
+ end
299
+ WEBrick::Daemon.start
300
+ File.open(@@pid_file, 'w') {|f| f.write("#{Process.pid}\n")}
301
+ end
302
+
303
+ new(options).run
304
+
305
+ rescue SystemExit
306
+ raise
307
+ rescue SignalException
308
+ exit
309
+ rescue Exception => e
310
+ $stderr.puts "Unhandled exception #{e.message}(#{e.class}):"
311
+ $stderr.puts "\t#{e.backtrace.join "\n\t"}"
312
+ exit -2
313
+ end
314
+
315
+ ##
316
+ # Prints a usage message to $stderr using +opts+ and exits
317
+
318
+ def self.usage(opts, message = nil)
319
+ if message then
320
+ $stderr.puts message
321
+ $stderr.puts
322
+ end
323
+
324
+ $stderr.puts opts
325
+ exit 1
326
+ end
327
+
328
+ ##
329
+ # Creates a new ARSendmail.
330
+ #
331
+ # Valid options are:
332
+ # <tt>:BatchSize</tt>:: Maximum number of emails to send per delay
333
+ # <tt>:Delay</tt>:: Delay between deliver attempts
334
+ # <tt>:Once</tt>:: Only attempt to deliver emails once when run is called
335
+ # <tt>:Verbose</tt>:: Be verbose.
336
+
337
+ def initialize(options = {})
338
+ options[:Delay] ||= 60
339
+ options[:MaxAge] ||= 86400 * 7
340
+
341
+ @batch_size = options[:BatchSize]
342
+ @delay = options[:Delay]
343
+ @once = options[:Once]
344
+ @verbose = options[:Verbose]
345
+ @max_age = options[:MaxAge]
346
+
347
+ @failed_auth_count = 0
348
+ end
349
+
350
+ ##
351
+ # Removes emails that have lived in the queue for too long. If max_age is
352
+ # set to 0, no emails will be removed.
353
+
354
+ def cleanup
355
+ return if @max_age == 0
356
+ timeout = Time.now - @max_age
357
+ conditions = ['last_send_attempt > 0 and created_on < ?', timeout]
358
+ mail = self.class.email_class.destroy_all conditions
359
+
360
+ log "expired #{mail.length} emails from the queue"
361
+ end
362
+
363
+ ##
364
+ # Delivers +emails+ to ActionMailer's SMTP server and destroys them.
365
+
366
+ def deliver(emails)
367
+ settings = [
368
+ smtp_settings[:domain],
369
+ (smtp_settings[:user] || smtp_settings[:user_name]),
370
+ smtp_settings[:password],
371
+ smtp_settings[:authentication]
372
+ ]
373
+
374
+ smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
375
+ if smtp.respond_to?(:enable_starttls_auto)
376
+ smtp.enable_starttls_auto unless smtp_settings[:tls] == false
377
+ else
378
+ settings << smtp_settings[:tls]
379
+ end
380
+
381
+ smtp.start(*settings) do |session|
382
+ @failed_auth_count = 0
383
+ until emails.empty? do
384
+ email = emails.shift
385
+ begin
386
+ res = session.send_message email.mail, email.from, email.to
387
+ email.destroy
388
+ log "sent email %011d from %s to %s: %p" %
389
+ [email.id, email.from, email.to, res]
390
+ rescue Net::SMTPFatalError => e
391
+ log "5xx error sending email %d, removing from queue: %p(%s):\n\t%s" %
392
+ [email.id, e.message, e.class, e.backtrace.join("\n\t")]
393
+ email.destroy
394
+ session.reset
395
+ rescue Net::SMTPServerBusy => e
396
+ log "server too busy, stopping delivery cycle"
397
+ return
398
+ rescue Net::SMTPUnknownError, Net::SMTPSyntaxError, TimeoutError, Timeout::Error => e
399
+ email.last_send_attempt = Time.now.to_i
400
+ email.save rescue nil
401
+ log "error sending email %d: %p(%s):\n\t%s" %
402
+ [email.id, e.message, e.class, e.backtrace.join("\n\t")]
403
+ session.reset
404
+ end
405
+ end
406
+ end
407
+ rescue Net::SMTPAuthenticationError => e
408
+ @failed_auth_count += 1
409
+ if @failed_auth_count >= MAX_AUTH_FAILURES then
410
+ log "authentication error, giving up: #{e.message}"
411
+ raise e
412
+ else
413
+ log "authentication error, retrying: #{e.message}"
414
+ end
415
+ sleep delay
416
+ rescue Net::SMTPServerBusy, SystemCallError, OpenSSL::SSL::SSLError
417
+ # ignore SMTPServerBusy/EPIPE/ECONNRESET from Net::SMTP.start's ensure
418
+ end
419
+
420
+ ##
421
+ # Prepares ar_sendmail for exiting
422
+
423
+ def do_exit
424
+ log "caught signal, shutting down"
425
+ self.class.remove_pid_file
426
+ exit 130
427
+ end
428
+
429
+ ##
430
+ # Returns emails in email_class that haven't had a delivery attempt in the
431
+ # last 300 seconds.
432
+
433
+ def find_emails
434
+ options = { :conditions => ['last_send_attempt < ?', Time.now.to_i - 300] }
435
+ options[:limit] = batch_size unless batch_size.nil?
436
+ mail = self.class.email_class.find :all, options
437
+
438
+ log "found #{mail.length} emails to send"
439
+ mail
440
+ end
441
+
442
+ ##
443
+ # Installs signal handlers to gracefully exit.
444
+
445
+ def install_signal_handlers
446
+ trap 'TERM' do do_exit end
447
+ trap 'INT' do do_exit end
448
+ end
449
+
450
+ ##
451
+ # Logs +message+ if verbose
452
+
453
+ def log(message)
454
+ $stderr.puts message if @verbose
455
+ ActionMailer::Base.logger.info "ar_sendmail: #{message}"
456
+ end
457
+
458
+ ##
459
+ # Scans for emails and delivers them every delay seconds. Only returns if
460
+ # once is true.
461
+
462
+ def run
463
+ install_signal_handlers
464
+
465
+ loop do
466
+ begin
467
+ cleanup
468
+ emails = find_emails
469
+ deliver(emails) unless emails.empty?
470
+ rescue ActiveRecord::Transactions::TransactionError
471
+ end
472
+ break if @once
473
+ sleep @delay
474
+ end
475
+ end
476
+
477
+ ##
478
+ # Proxy to ActionMailer::Base::smtp_settings. See
479
+ # http://api.rubyonrails.org/classes/ActionMailer/Base.html
480
+ # for instructions on how to configure ActionMailer's SMTP server.
481
+ #
482
+ # Falls back to ::server_settings if ::smtp_settings doesn't exist for
483
+ # backwards compatibility.
484
+
485
+ def smtp_settings
486
+ ActionMailer::Base.smtp_settings rescue ActionMailer::Base.server_settings
487
+ end
488
+
489
+ end
@@ -0,0 +1,31 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class ArMailerRails3Generator < Rails::Generators::NamedBase
5
+ include Rails::Generators::Migration
6
+
7
+ def create_ar_mailer_files
8
+ self.class.check_class_collision class_name
9
+ template('ar_mailer.rb', 'config/initializers/ar_mailer.rb')
10
+ template('model.rb', File.join('app/models', class_path, "#{file_name}.rb"))
11
+ migration_template 'migration.rb', "db/migrate/create_#{file_path.gsub(/\//, '_').pluralize}.rb"
12
+ end
13
+
14
+ def self.source_root
15
+ File.join(File.dirname(__FILE__), 'templates')
16
+ end
17
+
18
+ # Implement the required interface for Rails::Generators::Migration.
19
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
20
+ def self.next_migration_number(dirname)
21
+ if ActiveRecord::Base.timestamped_migrations
22
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
23
+ else
24
+ "%.3d" % (current_migration_number(dirname) + 1)
25
+ end
26
+ end
27
+
28
+ def self.banner
29
+ "Usage: #{$0} ar_mailer_rails3 EmailModelName (default: Email)"
30
+ end
31
+ end
@@ -0,0 +1,2 @@
1
+ ActionMailer::Base.add_delivery_method :active_record, ArMailerRails3::ActiveRecord, :email_class => <%= class_name %>
2
+ ActionMailer::Base.delivery_method = :active_record
@@ -0,0 +1,15 @@
1
+ class Create<%= migration_class_name.gsub(/::/, '') %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= table_name %> do |t|
4
+ t.column :from, :string
5
+ t.column :to, :string
6
+ t.column :last_send_attempt, :integer, :default => 0
7
+ t.column :mail, :text
8
+ t.column :created_on, :datetime
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :<%= table_name %>
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ end
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?
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ar_mailer_rails3
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 2
7
+ - 1
8
+ - 8
9
+ version: 2.1.8
10
+ platform: ruby
11
+ authors:
12
+ - Yuanyi Zhang
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-10 00:00:00 +08:00
18
+ default_executable: ar_sendmail_rails3
19
+ dependencies: []
20
+
21
+ description: ArMailer wrapper for Rails 3
22
+ email: zhangyuanyi@gmail.com
23
+ executables:
24
+ - ar_sendmail_rails3
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE.txt
29
+ - README.rdoc
30
+ files:
31
+ - .gitignore
32
+ - History.txt
33
+ - LICENSE.txt
34
+ - README.rdoc
35
+ - Rakefile
36
+ - VERSION
37
+ - bin/ar_sendmail_rails3
38
+ - lib/ar_mailer_rails3.rb
39
+ - lib/ar_mailer_rails3/active_record.rb
40
+ - lib/ar_mailer_rails3/ar_sendmail.rb
41
+ - lib/generators/ar_mailer_rails3/ar_mailer_rails3_generator.rb
42
+ - lib/generators/ar_mailer_rails3/templates/ar_mailer.rb
43
+ - lib/generators/ar_mailer_rails3/templates/migration.rb
44
+ - lib/generators/ar_mailer_rails3/templates/model.rb
45
+ - lib/smtp_tls.rb
46
+ - test/test_armailer.rb
47
+ - test/test_arsendmail.rb
48
+ - test/test_helper.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/yzhang/ar_mailer_rails3
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.6
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: ArMailer wrapper for Rails 3
79
+ test_files: []
80
+