fast-mailer 0.0.1 → 0.1.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/README.md +12 -1
- data/VERSION +1 -1
- data/bin/autotest +14 -0
- data/bin/htmldiff +14 -0
- data/bin/ldiff +14 -0
- data/bin/rake +14 -0
- data/bin/rspec +14 -0
- data/bin/tt +14 -0
- data/bin/unit_diff +14 -0
- data/lib/fast-mailer/configuration.rb +5 -19
- data/lib/fast-mailer/mailer.rb +62 -0
- data/lib/fast-mailer/mock_smtp.rb +44 -0
- data/lib/fast-mailer/smtp.rb +39 -19
- data/lib/fast-mailer.rb +17 -0
- metadata +34 -11
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@ FastMailer
|
|
|
3
3
|
|
|
4
4
|
FastMailer is a collection of helpers that aims to help with sending email.
|
|
5
5
|
Specifically, it allows for convenient configuration and better throughput
|
|
6
|
-
when sending multiple mails.
|
|
6
|
+
when sending multiple mails using SMTP.
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
Configuration
|
|
@@ -55,6 +55,17 @@ email, we can send multiple emails using a single connection.
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
Testing
|
|
59
|
+
-------
|
|
60
|
+
|
|
61
|
+
To enable testing, first run
|
|
62
|
+
|
|
63
|
+
FastMailer.test_mode = true
|
|
64
|
+
|
|
65
|
+
This will cause FastMailer::SMTP to use FastMailer::MockSMTP rather than Net::SMTP.
|
|
66
|
+
You can then find your sent emails in FastMailer::MockSMTP.deliveries.
|
|
67
|
+
|
|
68
|
+
|
|
58
69
|
Coming features
|
|
59
70
|
---------------
|
|
60
71
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0
|
|
1
|
+
0.1.0
|
data/bin/autotest
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'autotest' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('autotest', 'autotest')
|
data/bin/htmldiff
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'htmldiff' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('diff-lcs', 'htmldiff')
|
data/bin/ldiff
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'ldiff' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('diff-lcs', 'ldiff')
|
data/bin/rake
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'rake' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('rake', 'rake')
|
data/bin/rspec
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'rspec' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/bin/tt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'tt' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('treetop', 'tt')
|
data/bin/unit_diff
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'unit_diff' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
|
|
10
|
+
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'bundler/setup'
|
|
13
|
+
|
|
14
|
+
load Gem.bin_path('autotest', 'unit_diff')
|
|
@@ -3,27 +3,13 @@
|
|
|
3
3
|
module FastMailer
|
|
4
4
|
class Configuration
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def self.smtp_configuration(options = nil)
|
|
12
|
-
TEST_CONFIGURATION
|
|
6
|
+
def self.smtp_configuration(options = nil)
|
|
7
|
+
if options.is_a? Hash
|
|
8
|
+
options
|
|
9
|
+
else
|
|
10
|
+
eval(File.read(options || File.expand_path("~/.config/smtp.rb")))
|
|
13
11
|
end
|
|
14
12
|
end
|
|
15
13
|
|
|
16
|
-
def self.disable_testing!
|
|
17
|
-
def self.smtp_configuration(options = nil)
|
|
18
|
-
if options.is_a? Hash
|
|
19
|
-
options
|
|
20
|
-
else
|
|
21
|
-
eval(File.read(options || File.expand_path("~/.config/smtp.rb")))
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
disable_testing!
|
|
27
|
-
|
|
28
14
|
end
|
|
29
15
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module FastMailer
|
|
2
|
+
class Mailer
|
|
3
|
+
|
|
4
|
+
def initialize(options = nil)
|
|
5
|
+
@options = options
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def send_all(mail_generator)
|
|
9
|
+
@mail_generator = mail_generator
|
|
10
|
+
@mutex = Mutex.new
|
|
11
|
+
|
|
12
|
+
tcount = (@options && @options[:max_connections]) || 1
|
|
13
|
+
threads = []
|
|
14
|
+
|
|
15
|
+
if tcount > 1
|
|
16
|
+
tcount.times do |n|
|
|
17
|
+
threads << Thread.new(n) do |tid|
|
|
18
|
+
send_until_done
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
threads.each { |thr| thr.join }
|
|
23
|
+
else
|
|
24
|
+
send_until_done
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
def send_until_done
|
|
31
|
+
smtp = FastMailer::SMTP.new @options
|
|
32
|
+
while (true)
|
|
33
|
+
begin
|
|
34
|
+
peek_mail
|
|
35
|
+
smtp.open do
|
|
36
|
+
while true
|
|
37
|
+
smtp.deliver next_mail
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
raise e if StopIteration === e
|
|
42
|
+
sleep 2 unless FastMailer.test_mode
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
rescue StopIteration
|
|
46
|
+
# Expected.
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def next_mail
|
|
50
|
+
@mutex.synchronize do
|
|
51
|
+
@mail_generator.next
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def peek_mail
|
|
56
|
+
@mutex.synchronize do
|
|
57
|
+
@mail_generator.peek
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
module FastMailer
|
|
3
|
+
# Original mockup from ActionMailer
|
|
4
|
+
class MockSMTP
|
|
5
|
+
|
|
6
|
+
def self.deliveries
|
|
7
|
+
@@deliveries
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(*args)
|
|
11
|
+
@@deliveries ||= []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sendmail(mail, from, to)
|
|
15
|
+
@@deliveries << [mail, from, to]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def start(*args)
|
|
19
|
+
yield self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.clear_deliveries
|
|
23
|
+
@@deliveries = []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# in the standard lib: net/smtp.rb line 577
|
|
27
|
+
# a TypeError is thrown unless this arg is a
|
|
28
|
+
# kind of OpenSSL::SSL::SSLContext
|
|
29
|
+
def enable_tls(context = nil)
|
|
30
|
+
if context && context.kind_of?(OpenSSL::SSL::SSLContext)
|
|
31
|
+
true
|
|
32
|
+
elsif context
|
|
33
|
+
raise TypeError,
|
|
34
|
+
"wrong argument (#{context.class})! "+
|
|
35
|
+
"(Expected kind of OpenSSL::SSL::SSLContext)"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def enable_starttls_auto
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/fast-mailer/smtp.rb
CHANGED
|
@@ -13,6 +13,11 @@ module FastMailer
|
|
|
13
13
|
# sending mail on the same connection.
|
|
14
14
|
class SMTP
|
|
15
15
|
|
|
16
|
+
include Hooks
|
|
17
|
+
|
|
18
|
+
define_hook :before_deliver
|
|
19
|
+
define_hook :after_deliver
|
|
20
|
+
|
|
16
21
|
attr_accessor :configuration
|
|
17
22
|
|
|
18
23
|
def initialize(options = nil)
|
|
@@ -25,7 +30,7 @@ module FastMailer
|
|
|
25
30
|
configuration[:host] ||= configuration[:address]
|
|
26
31
|
configuration[:username] ||= configuration[:user_name]
|
|
27
32
|
|
|
28
|
-
@smtp =
|
|
33
|
+
@smtp = connection_class.new(configuration[:host], configuration[:port])
|
|
29
34
|
if configuration[:enable_starttls_auto]
|
|
30
35
|
smtp.enable_starttls_auto if smtp.respond_to?(:enable_starttls_auto)
|
|
31
36
|
end
|
|
@@ -49,30 +54,45 @@ module FastMailer
|
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
private
|
|
57
|
+
def connection_class
|
|
58
|
+
FastMailer.test_mode ? FastMailer::MockSMTP : Net::SMTP
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def skip_delivery!
|
|
62
|
+
@skip_delivery = true
|
|
63
|
+
end
|
|
64
|
+
|
|
52
65
|
def perform_delivery(mail)
|
|
66
|
+
run_hook :before_deliver, mail
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
if !@skip_delivery
|
|
69
|
+
# Set the envelope from to be either the return-path, the sender or the first from address
|
|
70
|
+
envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
|
|
71
|
+
if envelope_from.blank?
|
|
72
|
+
raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
|
|
73
|
+
end
|
|
59
74
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
|
|
76
|
+
if destinations.blank?
|
|
77
|
+
raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
|
|
78
|
+
end
|
|
64
79
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
message ||= mail.encoded if mail.respond_to?(:encoded)
|
|
81
|
+
if message.blank?
|
|
82
|
+
raise ArgumentError.new('A encoded content is required to send a message')
|
|
83
|
+
end
|
|
69
84
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
begin
|
|
86
|
+
@smtp.sendmail(message, envelope_from, destinations)
|
|
87
|
+
run_hook :after_deliver, mail
|
|
88
|
+
rescue Exception => e
|
|
89
|
+
@smtp = nil
|
|
90
|
+
run_hook :after_deliver, mail, e
|
|
91
|
+
raise e
|
|
92
|
+
end
|
|
75
93
|
end
|
|
94
|
+
ensure
|
|
95
|
+
@skip_delivery = false
|
|
76
96
|
end
|
|
77
97
|
|
|
78
98
|
end
|
data/lib/fast-mailer.rb
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
|
|
2
2
|
require 'mail'
|
|
3
|
+
require 'hooks'
|
|
3
4
|
|
|
4
5
|
require 'fast-mailer/configuration'
|
|
5
6
|
require 'fast-mailer/smtp'
|
|
7
|
+
require 'fast-mailer/mailer'
|
|
8
|
+
|
|
9
|
+
module FastMailer
|
|
10
|
+
|
|
11
|
+
class <<self
|
|
12
|
+
def test_mode=(value)
|
|
13
|
+
require 'fast-mailer/mock_smtp' if value
|
|
14
|
+
@@test_mode = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_mode
|
|
18
|
+
@@test_mode ||= false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
metadata
CHANGED
|
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
|
4
4
|
prerelease: false
|
|
5
5
|
segments:
|
|
6
6
|
- 0
|
|
7
|
-
- 0
|
|
8
7
|
- 1
|
|
9
|
-
|
|
8
|
+
- 0
|
|
9
|
+
version: 0.1.0
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Erik Hansson
|
|
@@ -14,7 +14,7 @@ autorequire:
|
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
16
|
|
|
17
|
-
date: 2010-
|
|
17
|
+
date: 2010-10-01 00:00:00 +02:00
|
|
18
18
|
default_executable:
|
|
19
19
|
dependencies:
|
|
20
20
|
- !ruby/object:Gem::Dependency
|
|
@@ -46,9 +46,23 @@ dependencies:
|
|
|
46
46
|
type: :runtime
|
|
47
47
|
version_requirements: *id002
|
|
48
48
|
- !ruby/object:Gem::Dependency
|
|
49
|
-
name:
|
|
49
|
+
name: hooks
|
|
50
50
|
prerelease: false
|
|
51
51
|
requirement: &id003 !ruby/object:Gem::Requirement
|
|
52
|
+
none: false
|
|
53
|
+
requirements:
|
|
54
|
+
- - ~>
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
segments:
|
|
57
|
+
- 0
|
|
58
|
+
- 1
|
|
59
|
+
version: "0.1"
|
|
60
|
+
type: :runtime
|
|
61
|
+
version_requirements: *id003
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: bundler
|
|
64
|
+
prerelease: false
|
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
52
66
|
none: false
|
|
53
67
|
requirements:
|
|
54
68
|
- - ~>
|
|
@@ -59,11 +73,11 @@ dependencies:
|
|
|
59
73
|
- 0
|
|
60
74
|
version: 1.0.0
|
|
61
75
|
type: :development
|
|
62
|
-
version_requirements: *
|
|
76
|
+
version_requirements: *id004
|
|
63
77
|
- !ruby/object:Gem::Dependency
|
|
64
78
|
name: rspec
|
|
65
79
|
prerelease: false
|
|
66
|
-
requirement: &
|
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
67
81
|
none: false
|
|
68
82
|
requirements:
|
|
69
83
|
- - ~>
|
|
@@ -76,11 +90,11 @@ dependencies:
|
|
|
76
90
|
- 22
|
|
77
91
|
version: 2.0.0.beta.22
|
|
78
92
|
type: :development
|
|
79
|
-
version_requirements: *
|
|
93
|
+
version_requirements: *id005
|
|
80
94
|
- !ruby/object:Gem::Dependency
|
|
81
95
|
name: rake
|
|
82
96
|
prerelease: false
|
|
83
|
-
requirement: &
|
|
97
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
|
84
98
|
none: false
|
|
85
99
|
requirements:
|
|
86
100
|
- - ~>
|
|
@@ -91,11 +105,11 @@ dependencies:
|
|
|
91
105
|
- 7
|
|
92
106
|
version: 0.8.7
|
|
93
107
|
type: :development
|
|
94
|
-
version_requirements: *
|
|
108
|
+
version_requirements: *id006
|
|
95
109
|
- !ruby/object:Gem::Dependency
|
|
96
110
|
name: autotest
|
|
97
111
|
prerelease: false
|
|
98
|
-
requirement: &
|
|
112
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
|
99
113
|
none: false
|
|
100
114
|
requirements:
|
|
101
115
|
- - ">="
|
|
@@ -104,7 +118,7 @@ dependencies:
|
|
|
104
118
|
- 0
|
|
105
119
|
version: "0"
|
|
106
120
|
type: :development
|
|
107
|
-
version_requirements: *
|
|
121
|
+
version_requirements: *id007
|
|
108
122
|
description: Helps with sending emails fast, and with convenient configuration.
|
|
109
123
|
email:
|
|
110
124
|
- erik@bits2life.com
|
|
@@ -115,7 +129,16 @@ extensions: []
|
|
|
115
129
|
extra_rdoc_files: []
|
|
116
130
|
|
|
117
131
|
files:
|
|
132
|
+
- bin/autotest
|
|
133
|
+
- bin/htmldiff
|
|
134
|
+
- bin/ldiff
|
|
135
|
+
- bin/rake
|
|
136
|
+
- bin/rspec
|
|
137
|
+
- bin/tt
|
|
138
|
+
- bin/unit_diff
|
|
118
139
|
- lib/fast-mailer/configuration.rb
|
|
140
|
+
- lib/fast-mailer/mailer.rb
|
|
141
|
+
- lib/fast-mailer/mock_smtp.rb
|
|
119
142
|
- lib/fast-mailer/smtp.rb
|
|
120
143
|
- lib/fast-mailer.rb
|
|
121
144
|
- LICENCE
|