How to send emails with multiple, dynamic smtp using Actionmailer/Ruby on Rails

霸气de小男生 提交于 2019-11-27 18:12:34

Just set the ActionMailer::Base configuration values before each send action.

smtp_config = user.smtp_configuration

ActionMailer::Base.username = smtp_config.username
ActionMailer::Base.password = smtp_config.password
ActionMailer::Base.server = ..
ActionMailer::Base.port = ..
ActionMailer::Base.authentication = ..

Doing what is described in the other answer is not safe; you are setting class variables here, not instanced variables. If your Rails container is forking, you can do this, but now your application is depending on an implementation detail of the container. If you're not forking a new Ruby process, then you can have a race condition here.

You should have a model that is extending ActionMailer::Base, and when you call a method, it will return a Mail::Message object. That is your instance object and is where you should change your settings. The settings are also just a hash, so you can inline it.

msg = MyMailer.some_message
msg.delivery_method.settings.merge!(@user.mail_settings)
msg.deliver

Where in the above mail_settings returns some hash with appropriate keys IE

{:user_name=>username, :password=>password}

Here is a solution that I came up with based on the previous answers and comments. This uses an ActionMailer interceptor class.

class UserMailer < ActionMailer::Base
  default from: proc{ @user.mail_settings[:from_address] }      

  class DynamicSettingsInterceptor
     def self.delivering_email(message)
       message.delivery_method.settings.merge!(@user.mail_settings)
     end
   end
   register_interceptor DynamicSettingsInterceptor
end

For Rails 3.2.x

You can include AbstractController::Callbacks in your mailer class and the do a "after_filter :set_delivery_options" inside the mailer.

The set_delivery_options method would have access to instance variables setup by you in your mailer action and you can access the mail object as "message".

class MyNailer < ActionMailer::Base
  include AbstractController::Callbacks
  after_filter :set_delivery_options

  def nail_it(user)
    @user = user
    mail :subject => "you nailed it"
  end

  private

  def set_delivery_options
    message.delivery_method.settings.merge!(@user.company.smtp_creds)
  end
end
Saulius Morkevicius

in case somebody needs to set delivery method dynamically together with smtp credentials, u can use Mail::Message instance method to set delivery method together with it's variables so my addapted Aditya Sanghi version is:

class MainMailer < ActionMailer::Base
  WHATEVER_CONDITION = true # example only f.e. @ser

  include AbstractController::Callbacks
  after_filter :set_delivery_options

  private
  def set_delivery_options
    settings = {
    :address => 'smtp.mandrillapp.com', # intentionally
    :port => 587, # intentionally
    :domain => 'your_domain', #insetad of localhost.localdomain'
    :user_name => 'smtp_username',
    :password => 'smtp_password',
    :authentication => 'PLAIN' # or smthing else
}
    if WHATEVER_CONDITION
      message.delivery_method(:smtp, settings)
    end
  end
end
Sandro L

Since Rails 4+ it works to give the credentials directly via the delivery_method_options parameter:

class UserMailer < ApplicationMailer
  def welcome_email
    @user = params[:user]
    @url  = user_url(@user)
    delivery_options = { user_name: params[:company].smtp_user,
                         password: params[:company].smtp_password,
                         address: params[:company].smtp_host }
    mail(to: @user.email,
         subject: "Please see the Terms and Conditions attached",
         delivery_method_options: delivery_options)
  end
end

See Sending Emails with Dynamic Delivery Options (Rails Guides)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!