# frozen_string_literal: true require 'mail/smtp_envelope' module Mail # == Sending Email with SMTP # # Mail allows you to send emails using SMTP. This is done by wrapping Net::SMTP in # an easy to use manner. # # === Sending via SMTP server on Localhost # # Sending locally (to a postfix or sendmail server running on localhost) requires # no special setup. Just to Mail.deliver &block or message.deliver! and it will # be sent in this method. # # === Sending via MobileMe # # Mail.defaults do # delivery_method :smtp, { :address => "smtp.me.com", # :port => 587, # :domain => 'your.host.name', # :user_name => '', # :password => '', # :authentication => 'plain', # :enable_starttls_auto => true } # end # # === Sending via GMail # # Mail.defaults do # delivery_method :smtp, { :address => "smtp.gmail.com", # :port => 587, # :domain => 'your.host.name', # :user_name => '', # :password => '', # :authentication => 'plain', # :enable_starttls_auto => true } # end # # === Certificate verification # # When using TLS, some mail servers provide certificates that are self-signed # or whose names do not exactly match the hostname given in the address. # OpenSSL will reject these by default. The best remedy is to use the correct # hostname or update the certificate authorities trusted by your ruby. If # that isn't possible, you can control this behavior with # an :openssl_verify_mode setting. Its value may be either an OpenSSL # verify mode constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER), # or a string containing the name of an OpenSSL verify mode (none, peer). # # === Others # # Feel free to send me other examples that were tricky # # === Delivering the email # # Once you have the settings right, sending the email is done by: # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # Or by calling deliver on a Mail message # # mail = Mail.new do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # mail.deliver! class SMTP attr_accessor :settings DEFAULTS = { :address => 'localhost', :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls => nil, :enable_starttls_auto => true, :openssl_verify_mode => nil, :ssl => nil, :tls => nil, :open_timeout => 5, :read_timeout => 5 } def initialize(values) self.settings = DEFAULTS.merge(values) end def deliver!(mail) response = start_smtp_session do |smtp| Mail::SMTPConnection.new(:connection => smtp, :return_response => true).deliver!(mail) end settings[:return_response] ? response : self end private def start_smtp_session(&block) build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block) end def build_smtp_session Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp| tls = settings[:tls] || settings[:ssl] if !tls.nil? case tls when true smtp.enable_tls(ssl_context) when false smtp.disable_tls else raise ArgumentError, "Unrecognized :tls value #{settings[:tls].inspect}; expected true, false, or nil" end elsif settings.include?(:enable_starttls) && !settings[:enable_starttls].nil? case settings[:enable_starttls] when true smtp.enable_starttls(ssl_context) when false smtp.disable_starttls else raise ArgumentError, "Unrecognized :enable_starttls value #{settings[:enable_starttls].inspect}; expected true, false, or nil" end elsif settings.include?(:enable_starttls_auto) && !settings[:enable_starttls_auto].nil? case settings[:enable_starttls_auto] when true smtp.enable_starttls_auto(ssl_context) when false smtp.disable_starttls else raise ArgumentError, "Unrecognized :enable_starttls_auto value #{settings[:enable_starttls_auto].inspect}; expected true, false, or nil" end end smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout] smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout] end end # Allow SSL context to be configured via settings, for Ruby >= 1.9 # Just returns openssl verify mode for Ruby 1.8.x def ssl_context openssl_verify_mode = settings[:openssl_verify_mode] if openssl_verify_mode.kind_of?(String) openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}") end context = Net::SMTP.default_ssl_context context.verify_mode = openssl_verify_mode if openssl_verify_mode context.ca_path = settings[:ca_path] if settings[:ca_path] context.ca_file = settings[:ca_file] if settings[:ca_file] context end end end