Skip to content

Commit 9571fba

Browse files
authored
Merge branch 'mikel:master' into part_spec_master
2 parents b7ebe6b + 199a76b commit 9571fba

File tree

4 files changed

+155
-60
lines changed

4 files changed

+155
-60
lines changed

lib/mail/network/delivery_methods/smtp.rb

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class SMTP
8484
:password => nil,
8585
:authentication => nil,
8686
:enable_starttls => nil,
87-
:enable_starttls_auto => true,
87+
:enable_starttls_auto => nil,
8888
:openssl_verify_mode => nil,
8989
:ssl => nil,
9090
:tls => nil,
@@ -105,23 +105,64 @@ def deliver!(mail)
105105
end
106106

107107
private
108+
# `k` is said to be provided when `settings` has a non-nil value for `k`.
109+
def setting_provided?(k)
110+
!settings[k].nil?
111+
end
112+
113+
# Yields one of `:always`, `:auto` or `false` based on `enable_starttls` and `enable_starttls_auto` flags.
114+
# Yields `false` when `smtp_tls?`.
115+
def smtp_starttls
116+
return false if smtp_tls?
117+
118+
if setting_provided?(:enable_starttls) && settings[:enable_starttls]
119+
# enable_starttls: provided and truthy
120+
case settings[:enable_starttls]
121+
when :auto then :auto
122+
when :always then :always
123+
else
124+
:always
125+
end
126+
else
127+
# enable_starttls: not provided or false
128+
if setting_provided?(:enable_starttls_auto)
129+
settings[:enable_starttls_auto] ? :auto : false
130+
else
131+
# enable_starttls_auto: not provided
132+
# enable_starttls: when provided then false
133+
# use :auto when neither enable_starttls* provided
134+
setting_provided?(:enable_starttls) ? false : :auto
135+
end
136+
end
137+
end
138+
139+
def smtp_tls?
140+
setting_provided?(:tls) && settings[:tls] || setting_provided?(:ssl) && settings[:ssl]
141+
end
142+
108143
def start_smtp_session(&block)
109144
build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block)
110145
end
111146

112147
def build_smtp_session
148+
if smtp_tls? && (settings[:enable_starttls] || settings[:enable_starttls_auto])
149+
raise ArgumentError, ":enable_starttls and :tls are mutually exclusive. Set :tls if you're on an SMTPS connection. Set :enable_starttls if you're on an SMTP connection and using STARTTLS for secure TLS upgrade."
150+
end
151+
113152
Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
114-
if settings[:tls] || settings[:ssl]
115-
if smtp.respond_to?(:enable_tls)
116-
smtp.enable_tls(ssl_context)
117-
end
118-
elsif settings[:enable_starttls]
119-
if smtp.respond_to?(:enable_starttls)
153+
if smtp_tls?
154+
smtp.disable_starttls
155+
smtp.enable_tls(ssl_context)
156+
else
157+
smtp.disable_tls
158+
159+
case smtp_starttls
160+
when :always
120161
smtp.enable_starttls(ssl_context)
121-
end
122-
elsif settings[:enable_starttls_auto]
123-
if smtp.respond_to?(:enable_starttls_auto)
162+
when :auto
124163
smtp.enable_starttls_auto(ssl_context)
164+
else
165+
smtp.disable_starttls
125166
end
126167
end
127168

spec/mail/network/delivery_methods/smtp_spec.rb

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,10 @@
55
RSpec.describe "SMTP Delivery Method" do
66

77
before(:each) do
8+
MockSMTP.reset
9+
810
# Reset all defaults back to original state
9-
Mail.defaults do
10-
delivery_method :smtp, { :address => "localhost",
11-
:port => 25,
12-
:domain => 'localhost.localdomain',
13-
:user_name => nil,
14-
:password => nil,
15-
:authentication => nil,
16-
:enable_starttls => nil,
17-
:enable_starttls_auto => true,
18-
:openssl_verify_mode => nil,
19-
:tls => nil,
20-
:ssl => nil,
21-
:open_timeout => nil,
22-
:read_timeout => nil
23-
}
24-
end
25-
MockSMTP.clear_deliveries
11+
Mail.defaults { delivery_method :smtp, {} }
2612
end
2713

2814
describe "general usage" do
@@ -207,7 +193,7 @@ def redefine_verify_none(new_value)
207193

208194
message.deliver!
209195

210-
expect(MockSMTP.security).to eq :enable_starttls_auto
196+
expect(MockSMTP.starttls).to eq :auto
211197
end
212198

213199
it 'should allow forcing STARTTLS' do
@@ -216,19 +202,70 @@ def redefine_verify_none(new_value)
216202
217203
subject 'Re: No way!'
218204
body 'Yeah sure'
219-
delivery_method :smtp, { :address => "localhost",
220-
:port => 25,
221-
:domain => 'localhost.localdomain',
222-
:user_name => nil,
223-
:password => nil,
224-
:authentication => nil,
225-
:enable_starttls => true }
205+
delivery_method :smtp, { :enable_starttls => true }
206+
end
226207

208+
message.deliver!
209+
210+
expect(MockSMTP.starttls).to eq :always
211+
end
212+
213+
it 'should allow forcing STARTTLS via enable_starttls: :always (overriding :enable_starttls_auto)' do
214+
message = Mail.new do
215+
216+
217+
subject 'Re: No way!'
218+
body 'Yeah sure'
219+
delivery_method :smtp, { :enable_starttls => :always,
220+
:enable_starttls_auto => true }
227221
end
228222

229223
message.deliver!
230224

231-
expect(MockSMTP.security).to eq :enable_starttls
225+
expect(MockSMTP.starttls).to eq :always
226+
end
227+
228+
it 'should allow detecting STARTTLS via enable_starttls: :auto (overriding :enable_starttls_auto)' do
229+
message = Mail.new do
230+
231+
232+
subject 'Re: No way!'
233+
body 'Yeah sure'
234+
delivery_method :smtp, { :enable_starttls => :auto,
235+
:enable_starttls_auto => false }
236+
end
237+
238+
message.deliver!
239+
240+
expect(MockSMTP.starttls).to eq :auto
241+
end
242+
243+
it 'should allow disabling automatic STARTTLS' do
244+
message = Mail.new do
245+
246+
247+
subject 'Re: No way!'
248+
body 'Yeah sure'
249+
delivery_method :smtp, { :enable_starttls => false }
250+
end
251+
252+
message.deliver!
253+
254+
expect(MockSMTP.starttls).to eq false
255+
end
256+
257+
it 'raises when setting STARTTLS with tls' do
258+
message = Mail.new do
259+
260+
261+
subject 'Re: No way!'
262+
body 'Yeah sure'
263+
delivery_method :smtp, { :tls => true, :enable_starttls => :always }
264+
end
265+
266+
expect {
267+
message.deliver!
268+
}.to raise_error(ArgumentError, /:enable_starttls and :tls are mutually exclusive/)
232269
end
233270
end
234271

spec/mail/network_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ class MyRetriever; def initialize(settings); end; end
180180

181181
before(:each) do
182182
# Set the delivery method to test as the default
183-
MockSMTP.clear_deliveries
183+
MockSMTP.reset
184184
end
185185

186186
it "should deliver a mail message" do

spec/spec_helper.rb

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,44 @@ def strip_heredoc(string)
7171
string.gsub(/^[ \t]{#{indent}}/, '')
7272
end
7373

74+
class Net::SMTP
75+
class << self
76+
alias unstubbed_new new
77+
end
78+
79+
def self.new(*args)
80+
MockSMTP.new
81+
end
82+
end
83+
7484
# Original mockup from ActionMailer
7585
class MockSMTP
7686
attr_accessor :open_timeout, :read_timeout
7787

88+
def self.reset
89+
test = Net::SMTP.unstubbed_new('example.com')
90+
@@tls = test.tls?
91+
@@starttls = test.starttls?
92+
93+
@@deliveries = []
94+
end
95+
96+
reset
97+
7898
def self.deliveries
7999
@@deliveries
80100
end
81101

82-
def self.security
83-
@@security
102+
def self.tls
103+
@@tls
104+
end
105+
106+
def self.starttls
107+
@@starttls
84108
end
85109

86110
def initialize
87-
@@deliveries = []
88-
@@security = nil
111+
self.class.reset
89112
end
90113

91114
def sendmail(mail, from, to)
@@ -105,37 +128,31 @@ def finish
105128
return true
106129
end
107130

108-
def self.clear_deliveries
109-
@@deliveries = []
110-
end
111-
112-
def self.clear_security
113-
@@security = nil
114-
end
115-
116131
def enable_tls(context)
117-
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security && @@security != :enable_tls
118-
@@security = :enable_tls
132+
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@starttls == :always
133+
@@tls = true
119134
context
120135
end
121136

137+
def disable_tls
138+
@@tls = false
139+
end
140+
122141
def enable_starttls(context = nil)
123-
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security == :enable_tls
124-
@@security = :enable_starttls
142+
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@tls
143+
@@starttls = :always
125144
context
126145
end
127146

128147
def enable_starttls_auto(context)
129-
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security == :enable_tls
130-
@@security = :enable_starttls_auto
148+
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@tls
149+
@@starttls = :auto
131150
context
132151
end
133-
end
134-
135-
class Net::SMTP
136-
def self.new(*args)
137-
MockSMTP.new
152+
def disable_starttls
153+
@@starttls = false
138154
end
155+
139156
end
140157

141158
class MockPopMail

0 commit comments

Comments
 (0)