Rails ActionMailer с несколькими SMTP-серверами
Мне нужно использовать два разных SMTP-сервера в приложении Rails. Похоже, что путь ActionMailer построен, невозможно иметь разные smtp_settings для
подкласс. Я мог бы перезагрузить параметры smtp для каждого класса почтовой программы всякий раз, когда отправляется сообщение, но это испортит плагин ExceptionNotifier, который находится вне моего контроля (кроме случаев, когда я тоже с ним связан). У кого-нибудь есть решение/плагин для чего-то вроде
это?
В идеале я хотел бы иметь
class UserMailer < ActionMailer::Base; end
а затем установите в environment.rb
ActionMailer::Base.smtp_settings = standard_smtp_settings
UserMailer.smtp_settings = user_smtp_settings
Таким образом, большинство моих почтовых программ, включая ExceptionNotifier, будут загружать настройки по умолчанию, но UserMailer будет использовать оплаченную службу ретрансляции.
Ответы
Ответ 1
Основываясь на статье Oreilly, я придумал решение, которое я написал здесь:
http://transfs.com/devblog/2009/12/03/custom-smtp-settings-for-a-specific-actionmailer-subclass
Вот соответствующий код:
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
Ответ 2
Решение для Rails 4. 2+:
конфиг /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
конфигурации/среда /production.rb:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = Rails.application.secrets.gmail_smtp
Приложение/отправители /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
Приложение/отправители /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
Ответ 3
Для всех, кто подходит к этой проблеме с более поздними версиями (3+) Rails, попробуйте это
http://guides.rubyonrails.org/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options
Ответ 4
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 допускает динамические варианты доставки. Приведенный выше код взят прямо из руководства по основам действий, которое вы можете найти здесь: http://guides.rubyonrails.org/v4.0/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options
Благодаря этому можно иметь разные настройки smtp для каждого отправляемого вами электронного письма, или, как в вашем случае для разных подклассов, таких как UserMailer, OtherMailer и т.д.
Ответ 5
Пытался использовать опцию jkrall с Rails 3.2.1, но по какой-то причине она не переопределит конфигурацию по умолчанию, а сделает:
MyMailer.my_email.delivery_method.settings.merge!(SMTP_SETTINGS).deliver
Подобно http://www.scottw.com/multiple-smtp-servers-with-action-mailer, он сработал.
Ответ 6
Рельсы-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)
Ответ 7
Я боюсь, что это не выполнимо изначально.
Но вы можете немного обмануть его, изменив переменную @@smtp_settings в модели.
Там есть статья о Oreilly, которая объясняет это довольно хорошо, даже если они не совсем чисты.
http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html
Ответ 8
https://github.com/AnthonyCaliendo/action_mailer_callbacks
Я нашел, что этот плагин помог решить проблему для меня довольно легко (как в & 5 минут). Я просто изменяю @@smtp_settings для конкретной почтовой программы в before_deliver, а затем меняю ее на значения по умолчанию в after_deliver. Используя этот подход, мне нужно добавить обратные вызовы в почтовые программы, которым нужно @@smtp_settings, отличным от стандартного.
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
Ответ 9
Здесь другое решение, которое, хотя это выглядит нелепо, я думаю, немного чище и проще использовать в разных классах 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
пример Mailer:
class CustomMailer < ActionMailer::Base
extend FTTUtilites::ActionMailer::ClassMethods
include FTTUtilites::ActionMailer::InstanceMethods
end
Ответ 10
Решение для 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
Решение, вдохновленное Как отправлять электронные письма с несколькими динамическими smtp с помощью Actionmailer/Ruby on Rails
Ответ 11
Когда мне захотелось быструю проверку на консоли (Rails 5), я сделал следующее:
settings = { username: "" } # etc
mailer = MyMailer.some_method
mailer.delivery_method.settings.merge!(settings)
mailer.deliver