Rails ActionMailer con múltiples servidores SMTP

Tengo la necesidad de usar dos servidores smtp diferentes en una aplicación Rails. Parece que la forma en que se construye ActionMailer, no es posible tener diferentes smtp_settings para una subclase. Podría volver a cargar la configuración de smtp para cada clase de correo cada vez que se envíe un mensaje, pero eso confunde el complemento ExceptionNotifier que está fuera de mi control (a menos que yo también lo haga). ¿Alguien tiene una solución / plugin para algo como esto?

Idealmente me gustaría tener

class UserMailer < ActionMailer::Base; end 

y luego establecer en environment.rb

 ActionMailer::Base.smtp_settings = standard_smtp_settings UserMailer.smtp_settings = user_smtp_settings 

Por lo tanto, la mayoría de mis correos, incluido ExceptionNotifier, retomaría la configuración predeterminada, pero UserMailer usaría un servicio de retransmisión pagado.

Basado en el artículo de Oreilly, se me ocurrió la solución que escribí aquí: http://transfs.com/devblog/2009/12/03/custom-smtp-settings-for-a-specific-actionmailer-subclass

Aquí está el código relevante:

 class MailerWithCustomSmtp < ActionMailer::Base SMTP_SETTINGS = { :address => "smtp.gmail.com", :port => 587, :authentication => :plain, :user_name => "custom_account@transfs.com", :password => 'password', } def awesome_email(bidder, options={}) with_custom_smtp_settings do subject 'Awesome Email D00D!' recipients 'someone@test.com' from 'custom_reply_to@transfs.com' body 'Hope this works...' end end # Override the deliver! method so that we can reset our custom smtp server settings def deliver!(mail = @mail) out = super reset_smtp_settings if @_temp_smtp_settings out end private def with_custom_smtp_settings(&block) @_temp_smtp_settings = @@smtp_settings @@smtp_settings = SMTP_SETTINGS yield end def reset_smtp_settings @@smtp_settings = @_temp_smtp_settings @_temp_smtp_settings = nil end end 

Para cualquiera que se acerque a este problema con versiones posteriores (3+) de Rails, intente esto

http://guides.rubyonrails.org/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options

Solución para Rails 4.2+:

config / secrets.yml :

 production: gmail_smtp: :authentication: "plain" :address: "smtp.gmail.com" :port: 587 :domain: "zzz.com" :user_name: "zzz@zzz.com" :password: "zzz" :enable_starttls_auto: true mandrill_smtp: :authentication: "plain" :address: "smtp.mandrillapp.com" :port: 587 :domain: "zzz.com" :user_name: "zzz@zzz.com" :password: "zzz" :enable_starttls_auto: true mailgun_smtp: :authentication: "plain" :address: "smtp.mailgun.org" :port: 587 :domain: "zzz.com" :user_name: "zzz@zzz.com" :password: "zzz" :enable_starttls_auto: true 

config / environment / production.rb :

 config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = Rails.application.secrets.gmail_smtp 

app / mailers / application_mailer.rb :

 class ApplicationMailer < ActionMailer::Base default from: '"ZZZ" ' private def gmail_delivery mail.delivery_method.settings = Rails.application.secrets.gmail_smtp end def mandrill_delivery mail.delivery_method.settings = Rails.application.secrets.mandrill_smtp end def mailgun_delivery mail.delivery_method.settings = Rails.application.secrets.mailgun_smtp end end 

app / mailers / user_mailer.rb :

 class UserMailer < ApplicationMailer # after_action :gmail_delivery, only: [:notify_user] after_action :mandrill_delivery, only: [:newsletter] after_action :mailgun_delivery, only: [:newsletter2] def newsletter(user_id); '...' end # this will be sent through mandrill smtp def newsletter2(user_id); '...' end # this will be sent through mailgun smtp def notify_user(user_id); '...' end # this will be sent through gmail smtp end 
 class UserMailer < ActionMailer::Base def welcome_email(user, company) @user = user @url = user_url(@user) delivery_options = { user_name: company.smtp_user, password: company.smtp_password, address: company.smtp_host } mail(to: @user.email, subject: "Please see the Terms and Conditions attached", delivery_method_options: delivery_options) end end 

Rails 4 permite opciones de entrega dinámicas. El código anterior proviene directamente de la guía básica de Action Mailer, que puede encontrar aquí: http://guides.rubyonrails.org/v4.0/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options

Con esto, es posible tener diferentes configuraciones de smtp para cada correo electrónico que envíe, o, como en su caso de uso, para diferentes subclases como UserMailer, OtherMailer, etc.

Intenté usar la opción de jkrall con Rails 3.2.1, pero por alguna razón no anularía la configuración predeterminada, pero si lo hacía:

 MyMailer.my_email.delivery_method.settings.merge!(SMTP_SETTINGS).deliver 

Similar a http://www.scottw.com/multiple-smtp-servers-with-action-mailer , lo hizo funcionar.

Rieles-2.3. *

 # app/models/user_mailer.rb class UserMailer < ActionMailer::Base def self.smtp_settings USER_MAILER_SMTP_SETTINGS end def spam(user) recipients user.mail from 'spam@example.com' subject 'Enlarge whatever!' body :user => user content_type 'text/html' end end # config/environment.rb ActionMailer::Base.smtp_settings = standard_smtp_settings USER_MAILER_SMTP_SETTINGS = user_smtp_settings # From console or whatever... UserMailer.deliver_spam(user) 

Me temo que no es factible de forma nativa.
Pero puede engañarlo un poco modificando la variable @@ smtp_settings en el modelo.

Hay un artículo en Oreilly que lo explica bastante bien a pesar de que el código no está limpio en absoluto. http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html

https://github.com/AnthonyCaliendo/action_mailer_callbacks

Encontré que este complemento me ayudó a resolver el problema con bastante facilidad (como en <5 minutos). Simplemente cambio el @@ smtp_settings para un correo en particular en el before_deliver y luego lo cambio de nuevo a los valores predeterminados en el after_deliver. Usando este enfoque, solo tengo que agregar las devoluciones de llamada a los correos que necesitan @@ smtp_settings diferente al predeterminado.

 class CustomMailer < ActionMailer::Base before_deliver do |mail| self.smtp_settings = custom_settings end after_deliver do |mail| self.smtp_settings = default_settings end def some_message subject "blah" recipients "blah@blah.com" from "ruby.ninja@ninjaness.com" body "You can haz Ninja rb skillz!" attachment some_doc end end 

Aquí hay otra solución que, si bien parece ridícula, creo que es un poco más limpia y más fácil de reutilizar en diferentes clases de AM :: Base:

  module FTTUtilities module ActionMailer module ClassMethods def smtp_settings dict = YAML.load_file(RAILS_ROOT + "/config/custom_mailers.yml")[self.name.underscore] @custom_smtp_settings ||= HashWithIndifferentAccess.new(dict) end end module InstanceMethods def smtp_settings self.class.smtp_settings end end end end 

ejemplo de correo:

  class CustomMailer < ActionMailer::Base extend FTTUtilites::ActionMailer::ClassMethods include FTTUtilites::ActionMailer::InstanceMethods end 

Solución para Rails 3.2:

 class SomeMailer < ActionMailer::Base include AbstractController::Callbacks after_filter :set_delivery_options private def set_delivery_options settings = { :address => 'smtp.server', :port => 587, :domain => 'your_domain', :user_name => 'smtp_username', :password => 'smtp_password', :authentication => 'PLAIN' # or something } message.delivery_method.settings.merge!(settings) end end 

Solución inspirada en Cómo enviar correos electrónicos con múltiples smtp dynamics usando Actionmailer / Ruby on Rails

Cuando quise una prueba rápida en la consola (Rails 5) hice lo siguiente:

 settings = { username: "" } # etc mailer = MyMailer.some_method mailer.delivery_method.settings.merge!(settings) mailer.deliver