Ruby Mail, how to achieve SSL email
I have successfully sent email to a remote server using port their port 25 (non-secure) with this script:
require 'rubygems'
require 'mail'
options = { :address => "mail.domain.com",
:port => 25,
:domain => 'mail.domain.com',
:user_name => 'somedude@domain.com',
:password => 'topsecret',
:authentication => 'login',
:enable_starttls_auto => true }
Mail.defaults do
delivery_method :smtp, options
end
mail = Mail.new do
from 'someotherdude@otherdomain.com'
to 'somedude@domain.com'
subject 'This is a test email'
body File.read('body.txt')
end
puts mail.to_s
mail.deliver!
What I need to do now is use their SSL port 466. When I try it, I get the normal output detailing the message, then it pauses for about 2 minutes and coughs up this:
/usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/timeout.rb:60:in `rbuf_fill': execution expired (Timeout::Error)
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/protocol.rb:134:in `rbuf_fill'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/protocol.rb:116:in `readuntil'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/protocol.rb:126:in `readline'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/smtp.rb:911:in `recv_response'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/smtp.rb:554:in `do_start'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/smtp.rb:921:in `critical'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/smtp.rb:554:in `do_start'
from /usr/local/rvm/rubies/ruby-1.8.7-p249/lib/ruby/1.8/net/smtp.rb:525:in `start'
from /usr/local/rvm/gems/ruby-1.8.7-p249/gems/mail-2.2.10/lib/mail/network/delivery_methods/smtp.rb:127:in `deliver!'
from /usr/local/rvm/gems/ruby-1.8.7-p249/gems/mail-2.2.10/lib/mail/message.rb:243:in `deliver!'
开发者_JS百科from testmail.rb:30
I think this is because it cannot even begin the SSL authentication process. How do I do it?
Hmm reading the network/delivery_methods/smtp.rb, it doesn't look like it support Direct SSL. TLS isn't them same, as the connection starts out Plain Text and then Switches to SSL on the starttls command. Can you just use starttls on port 587?
pulling my comment up.
see
How to send mail with ruby over smtp with ssl (not with rails, no TLS for gmail)
Which suggests that you can monkey patch Net::SMTP to do it..
Ok kinda found the issue and can patch around it, but so far this solution is yucky.. but it does work :)
#!/usr/bin/env ruby
require 'rubygems'
require "openssl"
require "net/smtp"
require "mail"
Net::SMTP.class_eval do
def self.start( address, port = nil,
helo = 'localhost.localdomain',
user = nil, secret = nil, authtype = nil, use_tls = false,
use_ssl = true, &block) # :yield: smtp
new(address, port).start(helo, user, secret, authtype, use_tls, use_ssl, &block)
end
def start( helo = 'localhost.localdomain',
user = nil, secret = nil, authtype = nil, use_tls = false, use_ssl = true ) # :yield: smtp
start_method = use_tls ? :do_tls_start : use_ssl ? :do_ssl_start : :do_start
if block_given?
begin
send start_method, helo, user, secret, authtype
return yield(self)
ensure
do_finish
end
else
send start_method, helo, user, secret, authtype
return self
end
end
private
def do_tls_start(helodomain, user, secret, authtype)
raise IOError, 'SMTP session already started' if @started
check_auth_args user, secret
sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
@socket = Net::InternetMessageIO.new(sock)
@socket.read_timeout = 60 #@read_timeout
@socket.debug_output = STDERR #@debug_output
check_response(critical { recv_response() })
do_helo(helodomain)
raise 'openssl library not installed' unless defined?(OpenSSL)
starttls
ssl = OpenSSL::SSL::SSLSocket.new(sock)
ssl.sync_close = true
ssl.connect
@socket = Net::InternetMessageIO.new(ssl)
@socket.read_timeout = 60 #@read_timeout
@socket.debug_output = STDERR #@debug_output
do_helo(helodomain)
authenticate user, secret, authtype if user
@started = true
ensure
unless @started
# authentication failed, cancel connection.
@socket.close if not @started and @socket and not @socket.closed?
@socket = nil
end
end
def do_ssl_start(helodomain, user, secret, authtype)
raise IOError, 'SMTP session already started' if @started
check_auth_args user, secret
sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
raise 'openssl library not installed' unless defined?(OpenSSL)
ssl = OpenSSL::SSL::SSLSocket.new(sock)
ssl.sync_close = true
ssl.connect
@socket = Net::InternetMessageIO.new(ssl)
@socket.read_timeout = 60 #@read_timeout
@socket.debug_output = STDERR #@debug_output
check_response(critical { recv_response() })
do_helo(helodomain)
do_helo(helodomain)
authenticate user, secret, authtype if user
@started = true
ensure
unless @started
# authentication failed, cancel connection.
@socket.close if not @started and @socket and not @socket.closed?
@socket = nil
end
end
def do_helo(helodomain)
begin
if @esmtp
ehlo helodomain
else
helo helodomain
end
rescue Net::ProtocolError
if @esmtp
@esmtp = false
@error_occured = false
retry
end
raise
end
end
def starttls
getok('STARTTLS')
end
def quit
begin
getok('QUIT')
rescue EOFError, OpenSSL::SSL::SSLError
end
end
end
options = {
:address => "mail.domain.net",
:port => 466,
:domain => 'mail.domain.net',
:user_name => 'doon@domain.net',
:password => 'Secret!',
:authentication => 'login',
:use_ssl => true }
Mail.defaults do
delivery_method :smtp, options
end
mail = Mail.new do
from 'doon@domain.net'
to 'doon@someotherdomain.com'
subject 'This is a test email'
body File.read('body.txt')
end
puts mail.to_s
mail.deliver!
for some reason the use_ssl in the orig monkey patch doesn't make it in, and couple that with VERSION being undefined in Net::SMTP. So I changed that out, and forced use_ssl to be true, and was able to send email..
Did you mean to use port 465? That's the standard fallback port, not 466. You're likely timing out connecting to the wrong port.
精彩评论