Search code examples
ruby-on-railsgmail

Getting "Must issue a STARTTLS command first" when trying to send email


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.


Solution

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

    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
    

    config/environment.rb

    (add after everything else)

        require “smtp_tls”
    
        ActionMailer::Base.smtp_settings = {
        :address => “smtp.gmail.com”,
        :port => 587,
        :authentication => :plain,
        :user_name => “[email protected]”,
        :password => ’someonesPassword’
        } 
    

    Use ActionMailer as normal.