views:

586

answers:

3

I'm getting an error while trying to use the action_mailer_tls plugin to communicate with Gmail in my Rails app:

Must issue a STARTTLS command first

Others seem to have encountered this same problem:

The problem is that Gmail requires TLS authentication but the standard Ruby net/smtp library doesn't support TLS.

The article recommends following these steps, which I did:

Of course there is a helpful plugin created by Marc Chung to overcome this barrier. You can find it here and manually add it to your project or you can export it to your plugin directory.

  1. $ cd vendor/plugins
  2. $ svn export http://code.openrain.com/rails/action_mailer_tls/

Either way make sure you require 'smtp_tls'

Now all you need is to update your smtp_settings if you haven't done so already.

  1. ActionMailer::Base.smtp_settings = {
  2. :address => "smtp.gmail.com",
  3. :port => 587,
  4. :domain => "domain.com",
  5. :user_name => "[email protected]",
  6. :password => "password",
  7. :authentication => :plain
  8. }

Any suggestions for a better solution to talk to Gmail would be appreciated.

+4  A: 

I used Alexander Pomozov's solution to talk to Gmail from my Rails app. I believe the original article is gone but someone has reproduced the Google cache over here.

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 => “[email protected]”,
    :password => ’someonesPassword’
    } 

3. Use ActionMailer as normal.
ski
Instead of lib/smtp_tls.rb i put it in config/initializers/ ... both should work.
Sam
A: 

With Ruby 1.8.7 and Rails 2.3.4 (though it's been there for several releases), I've had success without the need for TLS-specific ActionMailer plugins by using the :enable_starttls_auto option. A sample config (from the production environment) looks like this:

ActionMailer::Base.smtp_settings = {
  :enable_starttls_auto => true,
  :address => "smtp.gmail.com",
  :port => 587,
  :domain => "domain.com",
  :authentication => :plain,
  :user_name => "username@domain",
  :password => "secret"
}
ry
A: 

I'm running rails 2.3.4 and although I thought (from googling around) you didn't require any plugins and only required the line

:enable_starttls_auto => true,

I actually only got it to work when I used the Alexander Pomozov solution posted by ski above (big thankyou to you guys). Any comments as to why? would be great but I'm just happy it works.

conspirisi
I have the same problem, and it is because we are still running on top of ruby 1.8.6. From the documentation: When set to true, detects if STARTTLS is enabled in your SMTP server and starts to use it. It works only on Ruby >= 1.8.7 and Ruby >= 1.9. Default is true.
nathanvda