Skip to content

Commit 269774d

Browse files
committed
Net::SMTP.start arguments are keyword arguments
The helo argument is not important, but the helo argument must be specified to specify the user and secret arguments. If helo, user, secret, and authtype arguments are keyword arguments, it is not necessary to specify the helo argument.
1 parent b0f8ed6 commit 269774d

File tree

2 files changed

+122
-22
lines changed

2 files changed

+122
-22
lines changed

lib/net/smtp.rb

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ class SMTPUnsupportedCommand < ProtocolError
146146
# The SMTP server will judge whether it should send or reject
147147
# the SMTP session by inspecting the HELO domain.
148148
#
149-
# Net::SMTP.start('your.smtp.server', 25,
150-
# 'mail.from.domain') { |smtp| ... }
149+
# Net::SMTP.start('your.smtp.server', 25
150+
# helo: 'mail.from.domain') { |smtp| ... }
151151
#
152152
# === SMTP Authentication
153153
#
@@ -157,15 +157,15 @@ class SMTPUnsupportedCommand < ProtocolError
157157
# SMTP.start/SMTP#start.
158158
#
159159
# # PLAIN
160-
# Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
161-
# 'Your Account', 'Your Password', :plain)
160+
# Net::SMTP.start('your.smtp.server', 25
161+
# user: 'Your Account', secret: 'Your Password', authtype: :plain)
162162
# # LOGIN
163-
# Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
164-
# 'Your Account', 'Your Password', :login)
163+
# Net::SMTP.start('your.smtp.server', 25
164+
# user: 'Your Account', secret: 'Your Password', authtype: :login)
165165
#
166166
# # CRAM MD5
167-
# Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
168-
# 'Your Account', 'Your Password', :cram_md5)
167+
# Net::SMTP.start('your.smtp.server', 25
168+
# user: 'Your Account', secret: 'Your Password', authtype: :cram_md5)
169169
#
170170
class SMTP < Protocol
171171

@@ -400,12 +400,16 @@ def debug_output=(arg)
400400
# SMTP session control
401401
#
402402

403+
#
404+
# :call-seq:
405+
# start(address, port = nil, helo: 'localhost', user: nil, secret: nil, authtype: nil) { |smtp| ... }
406+
# start(address, port = nil, helo = 'localhost', user = nil, secret = nil, authtype = nil) { |smtp| ... }
403407
#
404408
# Creates a new Net::SMTP object and connects to the server.
405409
#
406410
# This method is equivalent to:
407411
#
408-
# Net::SMTP.new(address, port).start(helo_domain, account, password, authtype)
412+
# Net::SMTP.new(address, port).start(helo: helo_domain, user: account, secret: password, authtype: authtype)
409413
#
410414
# === Example
411415
#
@@ -449,17 +453,26 @@ def debug_output=(arg)
449453
# * Net::ReadTimeout
450454
# * IOError
451455
#
452-
def SMTP.start(address, port = nil, helo = 'localhost',
453-
user = nil, secret = nil, authtype = nil,
454-
&block) # :yield: smtp
455-
new(address, port).start(helo, user, secret, authtype, &block)
456+
def SMTP.start(address, port = nil, *args, helo: nil,
457+
user: nil, secret: nil, password: nil, authtype: nil,
458+
&block)
459+
raise ArgumentError, "wrong number of arguments (given #{args.size + 2}, expected 1..6)" if args.size > 4
460+
helo ||= args[0] || 'localhost'
461+
user ||= args[1]
462+
secret ||= password || args[2]
463+
authtype ||= args[3]
464+
new(address, port).start(helo: helo, user: user, secret: secret, authtype: authtype, &block)
456465
end
457466

458467
# +true+ if the SMTP session has been started.
459468
def started?
460469
@started
461470
end
462471

472+
#
473+
# :call-seq:
474+
# start(helo: 'localhost', user: nil, secret: nil, authtype: nil) { |smtp| ... }
475+
# start(helo = 'localhost', user = nil, secret = nil, authtype = nil) { |smtp| ... }
463476
#
464477
# Opens a TCP connection and starts the SMTP session.
465478
#
@@ -487,7 +500,7 @@ def started?
487500
#
488501
# require 'net/smtp'
489502
# smtp = Net::SMTP.new('smtp.mail.server', 25)
490-
# smtp.start(helo_domain, account, password, authtype) do |smtp|
503+
# smtp.start(helo: helo_domain, user: account, secret: password, authtype: authtype) do |smtp|
491504
# smtp.send_message msgstr, 'from@example.com', ['dest@example.com']
492505
# end
493506
#
@@ -511,8 +524,13 @@ def started?
511524
# * Net::ReadTimeout
512525
# * IOError
513526
#
514-
def start(helo = 'localhost',
515-
user = nil, secret = nil, authtype = nil) # :yield: smtp
527+
def start(*args, helo: nil,
528+
user: nil, secret: nil, password: nil, authtype: nil)
529+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..4)" if args.size > 4
530+
helo ||= args[0] || 'localhost'
531+
user ||= args[1]
532+
secret ||= password || args[2]
533+
authtype ||= args[3]
516534
if block_given?
517535
begin
518536
do_start helo, user, secret, authtype

test/net/smtp/test_smtp.rb

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,99 @@ def test_eof_error_backtrace
184184
end
185185
end
186186

187+
def test_start
188+
port = fake_server_start
189+
smtp = Net::SMTP.start('localhost', port)
190+
smtp.quit
191+
end
192+
193+
def test_start_with_position_argument
194+
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
195+
smtp = Net::SMTP.start('localhost', port, 'myname', 'account', 'password', :plain)
196+
smtp.quit
197+
end
198+
199+
def test_start_with_keyword_argument
200+
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
201+
smtp = Net::SMTP.start('localhost', port, helo: 'myname', user: 'account', secret: 'password', authtype: :plain)
202+
smtp.quit
203+
end
204+
205+
def test_start_password_is_secret
206+
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
207+
smtp = Net::SMTP.start('localhost', port, helo: 'myname', user: 'account', password: 'password', authtype: :plain)
208+
smtp.quit
209+
end
210+
211+
def test_start_invalid_number_of_arguments
212+
err = assert_raise ArgumentError do
213+
Net::SMTP.start('localhost', 25, 'myname', 'account', 'password', :plain, :invalid_arg)
214+
end
215+
assert_equal('wrong number of arguments (given 7, expected 1..6)', err.message)
216+
end
217+
218+
def test_start_instance
219+
port = fake_server_start
220+
smtp = Net::SMTP.new('localhost', port)
221+
smtp.start
222+
smtp.quit
223+
end
224+
225+
def test_start_instance_with_position_argument
226+
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
227+
smtp = Net::SMTP.new('localhost', port)
228+
smtp.start('myname', 'account', 'password', :plain)
229+
smtp.quit
230+
end
231+
232+
def test_start_instance_with_keyword_argument
233+
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
234+
smtp = Net::SMTP.new('localhost', port)
235+
smtp.start(helo: 'myname', user: 'account', secret: 'password', authtype: :plain)
236+
smtp.quit
237+
end
238+
239+
def test_start_instance_password_is_secret
240+
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
241+
smtp = Net::SMTP.new('localhost', port)
242+
smtp.start(helo: 'myname', user: 'account', password: 'password', authtype: :plain)
243+
smtp.quit
244+
end
245+
246+
def test_start_instance_invalid_number_of_arguments
247+
smtp = Net::SMTP.new('localhost')
248+
err = assert_raise ArgumentError do
249+
smtp.start('myname', 'account', 'password', :plain, :invalid_arg)
250+
end
251+
assert_equal('wrong number of arguments (given 5, expected 0..4)', err.message)
252+
end
253+
187254
private
188255

189256
def accept(servers)
190-
loop do
191-
readable, = IO.select(servers.map(&:to_io))
192-
readable.each do |r|
193-
sock, = r.accept_nonblock(exception: false)
194-
next if sock == :wait_readable
195-
return sock
257+
Socket.accept_loop(servers) { |s, _| break s }
258+
end
259+
260+
def fake_server_start(helo: 'localhost', user: nil, password: nil)
261+
servers = Socket.tcp_server_sockets('localhost', 0)
262+
Thread.start do
263+
Thread.current.abort_on_exception = true
264+
sock = accept(servers)
265+
sock.puts "220 ready\r\n"
266+
assert_equal("EHLO #{helo}\r\n", sock.gets)
267+
sock.puts "220-servername\r\n220 AUTH PLAIN\r\n"
268+
if user
269+
credential = ["\0#{user}\0#{password}"].pack('m0')
270+
assert_equal("AUTH PLAIN #{credential}\r\n", sock.gets)
271+
sock.puts "235 2.7.0 Authentication successful\r\n"
196272
end
273+
assert_equal("QUIT\r\n", sock.gets)
274+
sock.puts "221 2.0.0 Bye\r\n"
275+
sock.close
276+
servers.each(&:close)
197277
end
278+
port = servers[0].local_address.ip_port
279+
return port
198280
end
199281
end
200282
end

0 commit comments

Comments
 (0)