Net::SMTP
class Net::SMTP
Parent:Net::Protocol
What is This Library?
此库提供了通过SMTP(简单邮件传输协议)发送Internet邮件的功能。有关SMTP本身的详细信息,请参阅RFC2821。
What is This Library NOT?
这个库不提供编写网络邮件的功能。你必须自己创建它们。如果您想要更好的邮件支持,请尝试RubyMail或TMail或在RubyGems.org或Ruby工具箱中搜索替代方案。
FYI:Internet邮件的官方文档是:RFC2822。
Examples
Sending Messages
在发送消息之前,您必须打开与SMTP服务器的连接。第一个参数是您的SMTP服务器的地址,第二个参数是端口号。使用::开始一个块是最简单的方法。这样,在执行该块后,SMTP连接会自动关闭。
require 'net/smtp'
Net::SMTP.start('your.smtp.server', 25) do |smtp|
# Use the SMTP object smtp only in this block.
end
用你的SMTP服务器替换'your.smtp.server'。通常您的系统管理员或互联网提供商为您提供服务器。
然后你可以发送消息。
msgstr = <<END_OF_MESSAGE
From: Your Name <your@mail.address>
To: Destination Address <someone@example.com>
Subject: test message
Date: Sat, 23 Jun 2001 16:26:43 +0900
Message-Id: <unique.message.id.string@example.com>
This is a test message.
END_OF_MESSAGE
require 'net/smtp'
Net::SMTP.start('your.smtp.server', 25) do |smtp|
smtp.send_message msgstr,
'your@mail.address',
'his_address@example.com'
end
Closing the Session
您必须在发送消息后通过调用finish方法关闭SMTP会话:
# using SMTP#finish
smtp = Net::SMTP.start('your.smtp.server', 25)
smtp.send_message msgstr, 'from@address', 'to@address'
smtp.finish
您还可以使用:: start / SMTP#start的块形式。这会自动关闭SMTP会话:
# using block form of SMTP.start
Net::SMTP.start('your.smtp.server', 25) do |smtp|
smtp.send_message msgstr, 'from@address', 'to@address'
end
我强烈推荐这个方案。这种形式更简单,更健壮。
HELO domain
在几乎所有情况下,您必须提供第三个参数:: start / SMTP#start。这是您所在的域名(主机发送邮件)。它被称为“HELO域”。SMTP服务器将通过检查HELO域来判断它是否应发送或拒绝SMTP会话。
Net::SMTP.start('your.smtp.server', 25,
'mail.from.domain') { |smtp| ... }
SMTP Authentication
Net :: SMTP类支持三种认证方案; PLAIN,LOGIN和CRAM MD5。(SMTP验证:RFC2554)要使用SMTP验证,请将额外参数传递给:: start / SMTP#start。
# PLAIN
Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
'Your Account', 'Your Password', :plain)
# LOGIN
Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
'Your Account', 'Your Password', :login)
# CRAM MD5
Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
'Your Account', 'Your Password', :cram_md5)
常量
CRAM_BUFSIZE DEFAULT_AUTH_TYPE
认证
IMASK OMASK Revision
Attributes
addressR
要连接到的SMTP服务器的地址。
esmtpRW
设置是否使用ESMTP。这应该在调用开始之前完成。请注意,如果在ESMTP模式下调用启动,并且由于ProtocolError导致连接失败,则SMTP对象将自动切换到纯SMTP模式并重试(但反之亦然)。
esmtp?RW
设置是否使用ESMTP。这应该在调用开始之前完成。请注意,如果在ESMTP模式下调用启动,并且由于ProtocolError导致连接失败,则SMTP对象将自动切换到纯SMTP模式并重试(但反之亦然)。
open_timeoutRW
秒等待尝试打开连接。如果在此时间内无法打开连接,则会引发Net :: OpenTimeout。默认值是30秒。
portR
要连接的SMTP服务器的端口号。
read_timeoutR
秒读等待一个块(通过一次读取(2)调用)。如果read(2)调用在此时间内未完成,则会引发Net :: ReadTimeout。默认值是60秒。
Public Class Methods
default_port() Show source
默认的SMTP端口号,25。
# File lib/net/smtp.rb, line 174
def SMTP.default_port
25
end
default_ssl_context()显示源文件
# File lib/net/smtp.rb, line 192
def SMTP.default_ssl_context
OpenSSL::SSL::SSLContext.new
end
default_ssl_port()
别名为:default_tls_port
default_submission_port() Show source
默认邮件提交端口号,587。
# File lib/net/smtp.rb, line 179
def SMTP.default_submission_port
587
end
default_tls_port() Show source
默认的SMTPS端口号,465。
# File lib/net/smtp.rb, line 184
def SMTP.default_tls_port
465
end
另外别名为:default_ssl_port
new(address, port = nil) Show source
创建一个新的Net :: SMTP对象。
address
是您的SMTP服务器的主机名或IP地址。port
是连接的端口; 它默认为端口25。
此方法不会打开TCP连接。如果你想一次做所有事情,你可以使用:: start而不是:: new。否则,请使用#start追踪:: new。
# File lib/net/smtp.rb, line 207
def initialize(address, port = nil)
@address = address
@port = (port || SMTP.default_port)
@esmtp = true
@capabilities = nil
@socket = nil
@started = false
@open_timeout = 30
@read_timeout = 60
@error_occurred = false
@debug_output = nil
@tls = false
@starttls = false
@ssl_context = nil
end
start(address, port = nil, helo = 'localhost', user = nil, secret = nil, authtype = nil) { |smtp| ... } Show source
创建一个新的Net :: SMTP对象并连接到服务器。
这种方法相当于:
Net::SMTP.new(address, port).start(helo_domain, account, password, authtype)
Example
Net::SMTP.start('your.smtp.server') do |smtp|
smtp.send_message msgstr, 'from@example.com', ['dest@example.com']
end
Block Usage
如果使用块调用,则新打开的Net :: SMTP对象被赋予块,并在块完成时自动关闭。如果在没有阻止的情况下调用,则新打开的Net :: SMTP对象将返回给调用者,并且调用者有责任在完成时关闭它。
Parameters
address
是您的smtp服务器的主机名或IP地址。
port
是连接的端口; 它默认为端口25。
helo
是客户端提供给服务器的HELO
域
(请参阅概述注释); 它默认为'localhost'。
如果需要或需要,其余参数用于SMTP验证。user
是帐户名称; secret
是您的密码或其他身份验证令牌; 并且authtype
是身份验证类型,其中包括:plain,:login或:cram_md5。请参阅概述说明中有关SMTP身份验证的讨论。
Errors
这种方法可能会引起:
- Net::SMTPAuthenticationError
- Net::SMTPServerBusy
- Net::SMTPSyntaxError
- Net::SMTPFatalError
- Net::SMTPUnknownError
- Net::OpenTimeout
- Net::ReadTimeout
- IOError
# File lib/net/smtp.rb, line 451
def SMTP.start(address, port = nil, helo = 'localhost',
user = nil, secret = nil, authtype = nil,
&block) # :yield: smtp
new(address, port).start(helo, user, secret, authtype, &block)
end
公共实例方法
auth_cram_md5(user, secret) Show source
# File lib/net/smtp.rb, line 750
def auth_cram_md5(user, secret)
check_auth_args user, secret
res = critical {
res0 = get_response('AUTH CRAM-MD5')
check_auth_continue res0
crammed = cram_md5_response(secret, res0.cram_md5_challenge)
get_response(base64_encode("#{user} #{crammed}"))
}
check_auth_response res
res
end
auth_login(user, secret) Show source
# File lib/net/smtp.rb, line 739
def auth_login(user, secret)
check_auth_args user, secret
res = critical {
check_auth_continue get_response('AUTH LOGIN')
check_auth_continue get_response(base64_encode(user))
get_response(base64_encode(secret))
}
check_auth_response res
res
end
auth_plain(user, secret) Show source
# File lib/net/smtp.rb, line 730
def auth_plain(user, secret)
check_auth_args user, secret
res = critical {
get_response('AUTH PLAIN ' + base64_encode("\0#{user}\0#{secret}"))
}
check_auth_response res
res
end
authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE) Show source
# File lib/net/smtp.rb, line 724
def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE)
check_auth_method authtype
check_auth_args user, secret
send auth_method(authtype), user, secret
end
capable_auth_types() Show source
返回此服务器上支持的身份验证方法 在打开SMTP会话之前,您无法获得有效的值。
# File lib/net/smtp.rb, line 279
def capable_auth_types
return [] unless @capabilities
return [] unless @capabilities['AUTH']
@capabilities['AUTH']
end
capable_cram_md5_auth?() Show source
如果服务器通告AUTH CRAM-MD5,则为true。在打开SMTP会话之前,您无法获得有效的值。
# File lib/net/smtp.rb, line 266
def capable_cram_md5_auth?
auth_capable?('CRAM-MD5')
end
capable_login_auth?() Show source
如果服务器通告AUTH LOGIN,则为true。在打开SMTP会话之前,您无法获得有效的值。
# File lib/net/smtp.rb, line 260
def capable_login_auth?
auth_capable?('LOGIN')
end
capable_plain_auth?() Show source
如果服务器通告AUTH PLAIN,则为true。在打开SMTP会话之前,您无法获得有效的值。
# File lib/net/smtp.rb, line 254
def capable_plain_auth?
auth_capable?('PLAIN')
end
capable_starttls?() Show source
如果服务器宣传STARTTLS,则为true。在打开SMTP会话之前,您无法获得有效的值。
# File lib/net/smtp.rb, line 242
def capable_starttls?
capable?('STARTTLS')
end
data(msgstr = nil) { |stream| ... } Show source
此方法发送消息。如果msgstr
给出,则将其作为消息发送。如果给出块,则产生消息编写器流。您必须在该块关闭前写入消息。
# Example 1 (by string)
smtp.data("From: john@example.com
To: betty@example.com
Subject: I found a bug
Check vm.c:58879.
")
# Example 2 (by block)
smtp.data {|f|
f.puts "From: john@example.com"
f.puts "To: betty@example.com"
f.puts "Subject: I found a bug"
f.puts ""
f.puts "Check vm.c:58879."
}
# File lib/net/smtp.rb, line 890
def data(msgstr = nil, &block) #:yield: stream
if msgstr and block
raise ArgumentError, "message and block are exclusive"
end
unless msgstr or block
raise ArgumentError, "message or block is required"
end
res = critical {
check_continue get_response('DATA')
socket_sync_bak = @socket.io.sync
begin
@socket.io.sync = false
if msgstr
@socket.write_message msgstr
else
@socket.write_message_by_block(&block)
end
ensure
@socket.io.flush
@socket.io.sync = socket_sync_bak
end
recv_response()
}
check_response res
res
end
debug_output=(arg) Show source
警告:此方法会导致严重的安全漏洞。仅使用此方法进行调试。
设置输出流以进行调试日志记录。你必须在开始之前调用它。
# example
smtp = Net::SMTP.new(addr, port)
smtp.set_debug_output $stderr
smtp.start do |smtp|
....
end
# File lib/net/smtp.rb, line 392
def debug_output=(arg)
@debug_output = arg
end
Also aliased as: set_debug_output
disable_ssl()
Alias for: disable_tls
disable_starttls() Show source
禁用此对象的SMTP / TLS(STARTTLS)。必须在建立连接之前调用才能起作用。
# File lib/net/smtp.rb, line 350
def disable_starttls
@starttls = false
@ssl_context = nil
end
disable_tls() Show source
禁用此对象的SMTP / TLS。必须在建立连接之前调用才能起作用。
# File lib/net/smtp.rb, line 306
def disable_tls
@tls = false
@ssl_context = nil
end
Also aliased as: disable_ssl
ehlo(domain) Show source
# File lib/net/smtp.rb, line 828
def ehlo(domain)
getok("EHLO #{domain}")
end
enable_ssl(context = SMTP.default_ssl_context)
Alias for: enable_tls
enable_starttls(context = SMTP.default_ssl_context) Show source
为此对象启用SMTP / TLS(STARTTLS)。context
是一个OpenSSL :: SSL :: SSLContext对象。
# File lib/net/smtp.rb, line 332
def enable_starttls(context = SMTP.default_ssl_context)
raise 'openssl library not installed' unless defined?(OpenSSL)
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @tls
@starttls = :always
@ssl_context = context
end
enable_starttls_auto(context = SMTP.default_ssl_context) Show source
如果服务器接受,则为此对象启用SMTP / TLS(STARTTLS)。context
是一个OpenSSL :: SSL :: SSLContext对象。
# File lib/net/smtp.rb, line 341
def enable_starttls_auto(context = SMTP.default_ssl_context)
raise 'openssl library not installed' unless defined?(OpenSSL)
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @tls
@starttls = :auto
@ssl_context = context
end
enable_tls(context = SMTP.default_ssl_context) Show source
为此对象启用SMTP / TLS(SMTPS:通过直接TLS连接的SMTP)。必须在建立连接之前调用才能起作用。context
是一个OpenSSL :: SSL :: SSLContext对象。
# File lib/net/smtp.rb, line 295
def enable_tls(context = SMTP.default_ssl_context)
raise 'openssl library not installed' unless defined?(OpenSSL)
raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @starttls
@tls = true
@ssl_context = context
end
Also aliased as: enable_ssl
finish() Show source
完成SMTP会话并关闭TCP连接。如果未启动,则引发IOError。
# File lib/net/smtp.rb, line 530
def finish
raise IOError, 'not yet started' unless started?
do_finish
end
helo(domain) Show source
# File lib/net/smtp.rb, line 824
def helo(domain)
getok("HELO #{domain}")
end
inspect() Show source
提供人类可读的类状态的字符串化。
# File lib/net/smtp.rb, line 224
def inspect
"#<#{self.class} #{@address}:#{@port} started=#{@started}>"
end
mailfrom(from_addr) Show source
# File lib/net/smtp.rb, line 832
def mailfrom(from_addr)
if $SAFE > 0
raise SecurityError, 'tainted from_addr' if from_addr.tainted?
end
getok("MAIL FROM:<#{from_addr}>")
end
open_message_stream(from_addr, *to_addrs) { |stream| ... } Show source
打开消息编写器流并将其提供给该块。该流只在该块中有效,并具有以下方法:
puts(str = '')
outputs STR and CR LF.
print(str)
outputs STR.
printf(fmt, *args)
outputs sprintf(fmt,*args).
write(str)
输出STR并返回写入字节的长度。
<<(str)
输出STR并返回自我。
如果在消息中找到单个CR(“r”)或LF(“n”),它将转换为CR LF对。您无法使用此方法发送二进制消息。
参数
from_addr
是表示源邮件地址的字符串。
to_addr
是一个字符串或字符串或字符串数组,表示目标邮件地址或地址。
Example
Net::SMTP.start('smtp.example.com', 25) do |smtp|
smtp.open_message_stream('from@example.com', ['dest@example.com']) do |f|
f.puts 'From: from@example.com'
f.puts 'To: dest@example.com'
f.puts 'Subject: test message'
f.puts
f.puts 'This is a test message.'
end
end
Errors
这种方法可能会引起:
- Net::SMTPServerBusy
- Net::SMTPSyntaxError
- Net::SMTPFatalError
- Net::SMTPUnknownError
- Net::ReadTimeout
- IOError
# File lib/net/smtp.rb, line 708
def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream
raise IOError, 'closed session' unless @socket
mailfrom from_addr
rcptto_list(to_addrs) {data(&block)}
end
还有别名:ready
quit() Show source
# File lib/net/smtp.rb, line 917
def quit
getok('QUIT')
end
rcptto(to_addr) Show source
# File lib/net/smtp.rb, line 860
def rcptto(to_addr)
if $SAFE > 0
raise SecurityError, 'tainted to_addr' if to_addr.tainted?
end
getok("RCPT TO:<#{to_addr}>")
end
rcptto_list(to_addrs) { || ... } Show source
# File lib/net/smtp.rb, line 839
def rcptto_list(to_addrs)
raise ArgumentError, 'mail destination not given' if to_addrs.empty?
ok_users = []
unknown_users = []
to_addrs.flatten.each do |addr|
begin
rcptto addr
rescue SMTPAuthenticationError
unknown_users << addr.dump
else
ok_users << addr
end
end
raise ArgumentError, 'mail destination not given' if ok_users.empty?
ret = yield
unless unknown_users.empty?
raise SMTPAuthenticationError, "failed to deliver for #{unknown_users.join(', ')}"
end
ret
end
read_timeout=(sec) Show source
设置要等到读取(2)调用超时的秒数。
# File lib/net/smtp.rb, line 373
def read_timeout=(sec)
@socket.read_timeout = sec if @socket
@read_timeout = sec
end
ready(from_addr, *to_addrs)
别名为:open_message_stream
rset() Show source
中止当前的邮件交易
# File lib/net/smtp.rb, line 816
def rset
getok('RSET')
end
send_mail(msgstr, from_addr, *to_addrs)
别名为:send_message
send_message(msgstr, from_addr, *to_addrs) Show source
发送msgstr
作为消息。找到的单个CR(“r”)和LF(“n”)msgstr
被转换为CR LF对。您无法使用此方法发送二进制消息。msgstr
应该包含消息标题和正文。
from_addr
是表示源邮件地址的字符串。
to_addr
是一个字符串或字符串或字符串数组,表示目标邮件地址或地址。
Example
Net::SMTP.start('smtp.example.com') do |smtp|
smtp.send_message msgstr,
'from@example.com',
['dest@example.com', 'dest2@example.com']
end
Errors
这种方法可能会引起:
- Net::SMTPServerBusy
- Net::SMTPSyntaxError
- Net::SMTPFatalError
- Net::SMTPUnknownError
- Net::ReadTimeout
- IOError
# File lib/net/smtp.rb, line 655
def send_message(msgstr, from_addr, *to_addrs)
raise IOError, 'closed session' unless @socket
mailfrom from_addr
rcptto_list(to_addrs) {data msgstr}
end
另外别名为:send_mail,sendmail
sendmail(msgstr, from_addr, *to_addrs)
别名为:send_message
set_debug_output(ARG)
别名为:debug_output =
ssl?()
别名为:tls?
start(helo ='localhost',user = nil,secret = nil,authtype = nil){| smtp | ...}显示源文件
打开TCP连接并启动SMTP会话。
Parameters
helo
是您将派遣邮件的HELO
域名
; 请参阅概述说明中的讨论。
如果这两个user
和secret
给出,SMTP身份验证将使用AUTH命令进行尝试。authtype
指定要尝试的认证类型; 它必须是以下之一:login,:plain和:cram_md5。请参阅概述中有关SMTP身份验证的注意事项。
Block Usage
当使用块调用此方法时,新启动的SMTP对象被赋予块,并在块调用完成后自动关闭。否则,完成后关闭会话是主叫方的责任。
Example
这与类方法:: start非常相似。
require 'net/smtp'
smtp = Net::SMTP.new('smtp.mail.server', 25)
smtp.start(helo_domain, account, password, authtype) do |smtp|
smtp.send_message msgstr, 'from@example.com', ['dest@example.com']
end
此方法(与:: start相反)的主要用途可能是设置调试(#set_debug_output)或ESMTP(#esmtp =),这必须在会话启动之前完成。
Errors
如果会话已经启动,则会引发IOError。
这种方法可能会引起:
- Net::SMTPAuthenticationError
- Net::SMTPServerBusy
- Net::SMTPSyntaxError
- Net::SMTPFatalError
- Net::SMTPUnknownError
- Net::OpenTimeout
- Net::ReadTimeout
- IOError
# File lib/net/smtp.rb, line 513
def start(helo = 'localhost',
user = nil, secret = nil, authtype = nil) # :yield: smtp
if block_given?
begin
do_start helo, user, secret, authtype
return yield(self)
ensure
do_finish
end
else
do_start helo, user, secret, authtype
return self
end
end
started?() Show source
true
如果SMTP会话已启动。
# File lib/net/smtp.rb, line 458
def started?
@started
end
starttls() Show source
# File lib/net/smtp.rb, line 820
def starttls
getok('STARTTLS')
end
starttls?() Show source
如果此对象使用STARTTLS,则返回真值。如果这个对象总是使用STARTTLS,则返回:always。如果此对象在服务器支持TLS时使用STARTTLS,则返回:auto。
# File lib/net/smtp.rb, line 316
def starttls?
@starttls
end
starttls_always?() Show source
如果此对象使用STARTTLS,则为true。
# File lib/net/smtp.rb, line 321
def starttls_always?
@starttls == :always
end
starttls_auto?() Show source
如果此对象在服务器通告STARTTLS时使用STARTTLS,则为true。
# File lib/net/smtp.rb, line 326
def starttls_auto?
@starttls == :auto
end
tls?() Show source
如果此对象使用SMTP / TLS(SMTPS),则返回true。
# File lib/net/smtp.rb, line 286
def tls?
@tls
end
Also aliased as: ssl?
私有实例方法
auth_capable?(type) Show source
# File lib/net/smtp.rb, line 270
def auth_capable?(type)
return nil unless @capabilities
return false unless @capabilities['AUTH']
@capabilities['AUTH'].include?(type)
end
auth_method(type) Show source
# File lib/net/smtp.rb, line 770
def auth_method(type)
"auth_#{type.to_s.downcase}".intern
end
base64_encode(str) Show source
# File lib/net/smtp.rb, line 783
def base64_encode(str)
# expects "str" may not become too long
[str].pack('m0')
end
capable?(key) Show source
# File lib/net/smtp.rb, line 246
def capable?(key)
return nil unless @capabilities
@capabilities[key] ? true : false
end
check_auth_args(用户,秘密,authtype = DEFAULT_AUTH_TYPE)显示源
# File lib/net/smtp.rb, line 774
def check_auth_args(user, secret, authtype = DEFAULT_AUTH_TYPE)
unless user
raise ArgumentError, 'SMTP-AUTH requested but missing user name'
end
unless secret
raise ArgumentError, 'SMTP-AUTH requested but missing secret phrase'
end
end
check_auth_continue(res) Show source
# File lib/net/smtp.rb, line 984
def check_auth_continue(res)
unless res.continue?
raise res.exception_class, res.message
end
end
check_auth_method(type) Show source
# File lib/net/smtp.rb, line 764
def check_auth_method(type)
unless respond_to?(auth_method(type), true)
raise ArgumentError, "wrong authentication type #{type}"
end
end
check_auth_response(res) Show source
# File lib/net/smtp.rb, line 978
def check_auth_response(res)
unless res.success?
raise SMTPAuthenticationError, res.message
end
end
check_continue(res) Show source
# File lib/net/smtp.rb, line 972
def check_continue(res)
unless res.continue?
raise SMTPUnknownError, "could not get 3xx (#{res.status}: #{res.string})"
end
end
check_response(res) Show source
# File lib/net/smtp.rb, line 966
def check_response(res)
unless res.success?
raise res.exception_class, res.message
end
end
cram_md5_response(secret, challenge) Show source
CRAM-MD5: RFC2195
# File lib/net/smtp.rb, line 792
def cram_md5_response(secret, challenge)
tmp = Digest::MD5.digest(cram_secret(secret, IMASK) + challenge)
Digest::MD5.hexdigest(cram_secret(secret, OMASK) + tmp)
end
cram_secret(secret, mask) Show source
# File lib/net/smtp.rb, line 799
def cram_secret(secret, mask)
secret = Digest::MD5.digest(secret) if secret.size > CRAM_BUFSIZE
buf = secret.ljust(CRAM_BUFSIZE, "\0")
0.upto(buf.size - 1) do |i|
buf[i] = (buf[i].ord ^ mask).chr
end
buf
end
critical() { || ... } Show source
# File lib/net/smtp.rb, line 956
def critical
return Response.parse('200 dummy reply code') if @error_occurred
begin
return yield()
rescue Exception
@error_occurred = true
raise
end
end
do_finish() Show source
# File lib/net/smtp.rb, line 610
def do_finish
quit if @socket and not @socket.closed? and not @error_occurred
ensure
@started = false
@error_occurred = false
@socket.close if @socket
@socket = nil
end
do_helo(helo_domain) Show source
# File lib/net/smtp.rb, line 598
def do_helo(helo_domain)
res = @esmtp ? ehlo(helo_domain) : helo(helo_domain)
@capabilities = res.capabilities
rescue SMTPError
if @esmtp
@esmtp = false
@error_occurred = false
retry
end
raise
end
do_start(helo_domain, user, secret, authtype) Show source
# File lib/net/smtp.rb, line 541
def do_start(helo_domain, user, secret, authtype)
raise IOError, 'SMTP session already started' if @started
if user or secret
check_auth_method(authtype || DEFAULT_AUTH_TYPE)
check_auth_args user, secret
end
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do
tcp_socket(@address, @port)
end
logging "Connection opened: #{@address}:#{@port}"
@socket = new_internet_message_io(tls? ? tlsconnect(s) : s)
check_response critical { recv_response() }
do_helo helo_domain
if starttls_always? or (capable_starttls? and starttls_auto?)
unless capable_starttls?
raise SMTPUnsupportedCommand,
"STARTTLS is not supported on this server"
end
starttls
@socket = new_internet_message_io(tlsconnect(s))
# helo response may be different after STARTTLS
do_helo helo_domain
end
authenticate user, secret, (authtype || DEFAULT_AUTH_TYPE) if user
@started = true
ensure
unless @started
# authentication failed, cancel connection.
s.close if s
@socket = nil
end
end
get_response(reqline) Show source
# File lib/net/smtp.rb, line 940
def get_response(reqline)
validate_line reqline
@socket.writeline reqline
recv_response()
end
getok(reqline) Show source
# File lib/net/smtp.rb, line 930
def getok(reqline)
validate_line reqline
res = critical {
@socket.writeline reqline
recv_response()
}
check_response res
res
end
logging(msg) Show source
# File lib/net/smtp.rb, line 1069
def logging(msg)
@debug_output << msg + "\n" if @debug_output
end
new_internet_message_io(s) Show source
# File lib/net/smtp.rb, line 593
def new_internet_message_io(s)
InternetMessageIO.new(s, read_timeout: @read_timeout,
debug_output: @debug_output)
end
recv_response() Show source
# File lib/net/smtp.rb, line 946
def recv_response
buf = ''
while true
line = @socket.readline
buf << line << "\n"
break unless line[3,1] == '-' # "210-PIPELINING"
end
Response.parse(buf)
end
ssl_socket(socket, context) Show source
# File lib/net/smtp.rb, line 574
def ssl_socket(socket, context)
OpenSSL::SSL::SSLSocket.new socket, context
end
tcp_socket(address, port) Show source
# File lib/net/smtp.rb, line 537
def tcp_socket(address, port)
TCPSocket.open address, port
end
tlsconnect(s) Show source
# File lib/net/smtp.rb, line 578
def tlsconnect(s)
verified = false
s = ssl_socket(s, @ssl_context)
logging "TLS connection started"
s.sync_close = true
ssl_socket_connect(s, @open_timeout)
if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
s.post_connection_check(@address)
end
verified = true
s
ensure
s.close unless verified
end
validate_line(line) Show source
# File lib/net/smtp.rb, line 923
def validate_line(line)
# A bare CR or LF is not allowed in RFC5321.
if /[\r\n]/ =~ line
raise ArgumentError, "A line must not contain CR or LF"
end
end