Skip to content

Commit d5be91d

Browse files
committed
Config via url
1 parent aba0b5f commit d5be91d

File tree

2 files changed

+110
-2
lines changed

2 files changed

+110
-2
lines changed

lib/mail/network/delivery_methods/smtp.rb

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22
require 'mail/smtp_envelope'
3+
require 'mail/utilities'
34

45
module Mail
56
# == Sending Email with SMTP
@@ -74,6 +75,65 @@ module Mail
7475
#
7576
# mail.deliver!
7677
class SMTP
78+
class UrlResolver
79+
80+
DEFAULTS = {
81+
"smtp" => {
82+
:address => 'localhost',
83+
:port => 25,
84+
:domain => 'localhost.localdomain',
85+
:enable_starttls_auto => true
86+
},
87+
"smtps" => {
88+
:address => 'localhost',
89+
:port => 465,
90+
:domain => 'localhost.localdomain',
91+
:enable_starttls_auto => false,
92+
:tls => true
93+
}
94+
}
95+
96+
def initialize(url)
97+
@uri = uri_parser.parse(url)
98+
@query = uri.query
99+
end
100+
101+
def to_hash
102+
config = raw_config
103+
config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
104+
config
105+
end
106+
107+
private
108+
attr_reader :uri
109+
110+
def raw_config
111+
scheme_defaults.merge(query_hash).merge({
112+
:address => uri.host,
113+
:port => uri.port,
114+
:user_name => uri.user,
115+
:password => uri.password
116+
}.delete_if {|_key, value| Utilities.blank?(value) })
117+
end
118+
119+
def uri_parser
120+
Utilities.uri_parser
121+
end
122+
123+
def query_hash
124+
@query_hash = begin
125+
result = Hash[(@query || "").split("&").map { |pair| k,v = pair.split("="); [k.to_sym, v] }]
126+
result[:open_timeout] &&= result[:open_timeout].to_i
127+
result[:read_timeout] &&= result[:read_timeout].to_i
128+
result
129+
end
130+
end
131+
132+
def scheme_defaults
133+
DEFAULTS[uri.scheme]
134+
end
135+
end
136+
77137
attr_accessor :settings
78138

79139
DEFAULTS = {
@@ -92,8 +152,13 @@ class SMTP
92152
:read_timeout => nil
93153
}
94154

95-
def initialize(values)
96-
self.settings = DEFAULTS.merge(values)
155+
def initialize(config)
156+
settings = DEFAULTS
157+
158+
if config.has_key?(:url)
159+
settings = settings.merge(UrlResolver.new(config.delete(:url)).to_hash)
160+
end
161+
self.settings = settings.merge(config)
97162
end
98163

99164
def deliver!(mail)

spec/mail/network/delivery_methods/smtp_spec.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,49 @@
2525
MockSMTP.clear_deliveries
2626
end
2727

28+
describe 'settings via url' do
29+
def smtp_delivery_settings_for_url(url)
30+
Mail.defaults { delivery_method :smtp, {:url => url} }
31+
32+
Mail.delivery_method.settings
33+
end
34+
35+
it 'provides smtp defaults' do
36+
expect(smtp_delivery_settings_for_url('smtp:///')).to \
37+
include(:address => 'localhost',
38+
:port => 25,
39+
:domain => 'localhost.localdomain',
40+
:enable_starttls_auto => true)
41+
end
42+
43+
it 'provides smtps defaults' do
44+
expect(smtp_delivery_settings_for_url('smtps:///')).to \
45+
include(:address => 'localhost',
46+
:port => 465,
47+
:domain => 'localhost.localdomain',
48+
:tls => true)
49+
end
50+
51+
it 'allows for all attributes to be set' do
52+
url = 'smtp://mailer.org:12345?domain=sender.org&authentication=plain&openssl_verify_mode=peer&tls=true&open_timeout=1&read_timeout=2'
53+
expect(smtp_delivery_settings_for_url(url)).to \
54+
include(:address => 'mailer.org',
55+
:port => 12345,
56+
:domain => 'sender.org',
57+
:authentication => 'plain',
58+
:openssl_verify_mode => 'peer',
59+
:tls => 'true',
60+
:open_timeout => 1,
61+
:read_timeout => 2)
62+
end
63+
64+
it 'escapes credentials' do
65+
expect(smtp_delivery_settings_for_url('smtps://user%40host:pw-with-%[email protected]')).to \
66+
include(:user_name => 'user@host',
67+
:password => 'pw-with-/')
68+
end
69+
end
70+
2871
describe "general usage" do
2972
it "dot-stuff unterminated last line of the message" do
3073
Mail.deliver do

0 commit comments

Comments
 (0)