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