ruby on rails - generate - Rails ActionMailer con mĂșltiples servidores SMTP
rails generate email (11)
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.
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
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 => "[email protected]",
:password => ''password'',
}
def awesome_email(bidder, options={})
with_custom_smtp_settings do
subject ''Awesome Email D00D!''
recipients ''[email protected]''
from ''[email protected]''
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
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
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:
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
Similar a http://www.scottw.com/multiple-smtp-servers-with-action-mailer , lo hizo funcionar.
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
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
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 ''[email protected]''
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)
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 dinámicos usando Actionmailer / Ruby on Rails
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: "[email protected]"
:password: "zzz"
:enable_starttls_auto: true
mandrill_smtp:
:authentication: "plain"
:address: "smtp.mandrillapp.com"
:port: 587
:domain: "zzz.com"
:user_name: "[email protected]"
:password: "zzz"
:enable_starttls_auto: true
mailgun_smtp:
:authentication: "plain"
:address: "smtp.mailgun.org"
:port: 587
:domain: "zzz.com"
:user_name: "[email protected]"
: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" <[email protected]>''
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
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 "[email protected]"
from "[email protected]"
body "You can haz Ninja rb skillz!"
attachment some_doc
end
end
MyMailer.my_email.delivery_method.settings.merge!(SMTP_SETTINGS).deliver
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.