How to Send Mail with Ruby Over Smtp with Ssl (Not with Rails, No Tls for Gmail)

Redmine : send mail via gmail error SSL_connect or STARTTLS

1.Save the following code within your rails app in lib/smtp_tls.rb:

require "openssl"
require "net/smtp"

Net::SMTP.class_eval do
private

def do_start(helodomain, user, secret, authtype)
raise IOError, 'SMTP session already started' if @started
check_auth_args user, secret, authtype if user or 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)

if starttls
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
do_helo(helodomain)
end

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') rescue return false
return true
end

def quit
begin
getok('QUIT')
rescue EOFError, OpenSSL::SSL::SSLError
end
end
end

2.Add this code to config/environment.rb (after everything else):

require “smtp_tls”

ActionMailer::Base.smtp_settings = {
:address => “smtp.gmail.com”,
:port => 587,
:authentication => :plain,
:user_name => “someone@openrain.com”,
:password => ’someonesPassword’
}

3.Use ActionMailer as normal.

Does Pony support SSL/TLS for GMail (Yes!)

Here's a link to a thread that should have your answers http://groups.google.com/group/sinatrarb/browse_thread/thread/97619e0469c29f30?pli=1

How do I set the SSL protocol needed for ActionMailer to use a TLS connection?

port:                 587,
...
tls: true,
enable_starttls_auto: true

According to the documentation ":ssl/:tls - Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection)". But port 587 is not for direct TLS but for TLS upgrade via the STARTTLS command. Direct TLS is done on port 465 instead if enabled.

Thus, your client tries to access a non-TLS connection with TLS and this results in this strange error. See also my explanation on a similar question where this happened with Perl not Ruby.

To solve the problem either use port 465 with tls (if enabled on the server) or use port 587 and rely on enable_starttls_auto that it will do a later upgrade to TLS.

Ruby Mail, how to achieve SSL email

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..

Sending mail with devise and Gmail smtp server

If you're still having problems with this try using these settings:

require 'tlsmail'    
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.smtp_settings = {
:enable_starttls_auto => true,
:address => 'smtp.gmail.com',
:port => 587,
:tls => true,
:domain => 'gmail.com', #you can also use google.com
:authentication => :plain,
:user_name => 'jatinkumar.nitk@gmail.com',
:password => '_secret_password'
}

Additionally I would recommend putting these settings in your config/environments/development.rb file instead of environment.rb so that you can specify different mailservers for each environment.

(Ruby) Getting Net::SMTP working with Gmail...?

I actually just got this working. Wrote a quick script to test it.

I was getting a different error than you were (requiring STARTTLS), I also found I had to use port 587 instead of 465.

I found the trick to get it working in a Rails plugin I found. (agilewebdevelopment.com/plugins/net_smtp_tls_support)

if you 'eval' this file (it adds tls support to the standard Net::SMTP library):

http://happiness-is-slavery.net/wp-content/rails-plugins/smtp_add_tls_support/lib/smtp_add_tls_support.rb

then run 'Net::SMTP.enable_tls()'

everything seems to work fine.

Here's my code:

require 'rubygems'
require 'net/smtp'

eval File.read("smtp_tls.rb")
Net::SMTP.enable_tls()
FROM_EMAIL = "REMOVED"
PASSWORD = "REMOVED"
TO_EMAIL = "REMOVED"

msgstr = <<END_OF_MESSAGE
From: Your Name <#{FROM_EMAIL}>
To: my phone <#{TO_EMAIL}>
Subject: text 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

Net::SMTP.start('smtp.gmail.com', 587, 'gmail.com',
FROM_EMAIL, PASSWORD, :plain) do |smtp|
smtp.send_message msgstr, FROM_EMAIL, TO_EMAIL
end

obviously, i downloaded the above mentioned file to the same directory and named it 'smtp_tls.rb'

Hope this helps!

NoMethodError (undefined method `timeout' for #Net::SMTP smtp.gmail.com:587 started=false):

Ok so the issue was that i had the tlsmail gem installed at some point. This gem replaces the smtp classes used for sending out emails. I removed the gem and i am good to go.



Related Topics



Leave a reply



Submit