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 будет использовать платную службу ретрансляции.

13.10.2009 12:22:53
Для большей справки, вот запрос на извлечение, который в итоге был объединен только с Rails 4, так как Rails 3.2 не принимал новые функции. github.com/rails/rails/pull/7397
polmiro 14.08.2013 18:17:20
Смотрите ответ @ wnm для Rails 4, со ссылкой на документацию. Это довольно просто сейчас. stackoverflow.com/a/34948143/456791
Bek 8.09.2016 14:17:06
11 ОТВЕТОВ

Боюсь, это не выполнимо изначально.
Но вы можете немного обмануть, изменив переменную @@ smtp_settings в модели.

На Oreilly есть статья, которая объясняет это довольно хорошо, хотя их код не совсем чистый. http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html

0
13.10.2009 14:28:43
Спасибо за ответ. Я видел эту статью, и именно это я имел в виду, перезагружая настройки smtp перед каждым письмом (что и сделала статья в методе load_settings). Это близко к решению, но оно портит ExceptionNotifier, потому что я не могу перезагрузить его настройки без изменения плагина. Я надеялся там на что-то более ремонтопригодное.
user189053 13.10.2009 20:55:06
К сожалению, из-за того, как это реализовано, это невозможно.
Damien MATHIEU 14.10.2009 06:20:40
Все возможно с достаточным количеством обезьяньих заплат.
tadman 22.12.2009 16:51:54
Пожалуйста, помогите объединить этот PR в рельсы. ( github.com/rails/rails/pull/7397 ). Это делает именно то, о чем думает ФП.
Aditya Sanghi 30.08.2012 07:04:15

Основываясь на статье Орейли, я нашел решение, о котором написал здесь: 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 => "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
21
5.12.2009 02:09:32
Спасибо за ответ - это выглядит как хорошее решение (хотя у меня недостаточно репутации, чтобы проголосовать за него). В итоге я переключился с ExceptionNotifier на HopToad, что снова сделало возможным решение O'Reilly.
user189053 5.12.2009 21:35:17
Я должен был добавить: domain => 'localhost: 3000',: authentication =>: plain,: enable_starttls_auto => true, чтобы заставить его работать, но это лучшее решение, которое я нашел
thenengah 19.06.2010 09:59:24
и локальный хост изменения курса: 3000 к соответствующему домену производства
thenengah 19.06.2010 09:59:57
Но, похоже, это связано с проблемами параллелизма, описанными в ответе @ jcalvert « Как отправлять электронные письма с несколькими динамическими протоколами SMTP, используя Actionmailer / Ruby on Rails» .
Hew Wolff 3.12.2013 23:05:40

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 "blah@blah.com"
    from "ruby.ninja@ninjaness.com"
    body "You can haz Ninja rb skillz!"
    attachment some_doc
  end

end
0
22.12.2010 17:22:07

Вот еще одно решение, которое, хотя и выглядит нелепо, но, на мой взгляд, немного чище и его проще использовать в разных классах 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

пример почтовика:

    class CustomMailer < ActionMailer::Base
        extend FTTUtilites::ActionMailer::ClassMethods
        include FTTUtilites::ActionMailer::InstanceMethods
    end
0
25.02.2011 23:31:49

Попытался использовать опцию 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
16.02.2012 13:15:57
к вашему сведению! возвращает хеш, у которого нет метода доставки.
Akshay Rawat 4.03.2013 19:00:01
В упомянутом сообщении блога изменился URL-адрес, и теперь его можно найти по адресу dev.scottw.com/multiple-smtp-servers-with-action-mailer .
Austin Ziegler 6.06.2013 17:38:53
Связанные - stackoverflow.com/a/6413630/242426 . Есть также запрос на извлечение, который был объединен с Rails 4+, чтобы добавить поддержку для этого из коробки - github.com/rails/rails/pull/7397
plainjimbo 24.06.2013 18:22:23

Рельсы-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)
2
23.03.2013 16:49:31

Если вы хотите решить эту проблему с более поздними версиями Rails (3+), попробуйте

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

10
29.11.2013 12:09:14
Это самое чистое решение!
hcarreras 25.02.2016 11:11:07
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 и т. Д.

18
22.01.2016 13:43:46
Лучший ответ. Отлично работает в Rails 4: D
Abel 4.04.2017 04:42:43

Решение для 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" <zzz@zzz.com>'

  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
12
18.04.2019 06:22:13

Решение для 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

0
23.05.2017 11:55:03

Когда я хотел провести быстрый тест в консоли (Rails 5), я сделал следующее:

settings = { username: "" } # etc
mailer = MyMailer.some_method
mailer.delivery_method.settings.merge!(settings)
mailer.deliver
0
20.01.2017 14:57:07