I am sending emails with the mail gem, using the very simple code below. When I'm sending an email, the smtp_account.user_name and the smtp_account.from could be e.g. support#thebestcompany.com. This causes the recipient to see that he has received an email from support (you know, in his inbox where he can get an overview of his last x emails). How can I specify this, so the recipient gets to see something more interesting, like e.g. The Best Company?
require 'mail'
class SmtpMails
def self.send_mails(smtp_account, to, subject, text)
options = {
:address => smtp_account.address,
:port => smtp_account.port,
:domain => smtp_account.domain,
:user_name => smtp_account.user_name,
:password => smtp_account.password,
:authentication => smtp_account.authentication,
:enable_starttls_auto => smtp_account.enable_starttls_auto
}
Mail.defaults do
elivery_method :smtp, options
end
mail = Mail.deliver do
to to
from smtp_account.from
subject subject
end
end
end
You'll need to add some additional information when specifying the sender of the email. The following code snippet should do what you want:
mail = Mail.deliver do
to to
from "The Best Company <#{smtp_account.from}>"
subject subject
end
Putting the email address between the < and > brackets is the standard practice for adding a friendly name for the email being sent.
mail.from.addresses
mail.sender.address
Try this.
Related
Can Rails' ApplicationMailer (formerly ActionMailer) be configured to use REST API instead of SMTP?
In other words, replace
self.smtp_settings = {
:address => ENV['MAILER_URL'],
:port => ENV['MAILER_PORT'],
:domain => ENV['MAILER_DOMAIN'],
:authentication => :login,
:user_name => ENV['MAILER_USER'],
:password => ENV['MAILER_PWD'],
:enable_starttls_auto => true
}
perhaps with something like
config.action_mailer.delivery_method = :rest_client # JUST A MADE UP EXAMPLE
config.action_mailer.rest_client = {
api_auth_header:{"Authorization" => "Bearer #{ENV['MY_REST_MAILER_API_KEY']}" ,
api_endpoint: ENV['MY_REST_MAILER_API_URL']
}
I see a specific gem for Sendgrid and other ESPs where they provide a gem, but I'm looking for a general ActionMailer-to-Rest solution where I can specify an arbitrary api endpoint, etc and not be tied to a gem (or a provider who provides a gem) and still have the power of the templating etc that ActionMailer provides.
It's not impossible to skip the ActionMailer class entirely and just write a new mailer class that uses RestClient, in fact we've done that for certain special cases. But for normal emails its slower, more error prone, and definitely more work to manually deal with template rendering etc etc each time you simply want to create a new email type (customer_thank_you.html.haml, customer_welcome.html.haml, etc etc).
I think you can do this if you create a custom delivery_method for ActionMailer.
To do it, you'll need to:
Write a new class that responds to a couple methods
Register your delivery_method
Configure action_mailer to use it in your config
A scaffold of what it might look like in practice could be something like this:
# lib/rest_mail.rb
# ActionMailer will instantiate this class to send the email.
class RestMail
# initialize is called with the settings provided from your config
def initialize(settings)
#settings = settings
end
# deliver! is the only other required method. It is passed the mail object to send.
# mail.encoded returns the email in the format needed to send it.
# Look at other mail delivery methods for inspiration (Mail::Sendmail, Mail::FileDelivery, Mail::SMTP, etc)
def deliver!(mail)
#client.post(url: #settings['url'], payload: mail.encoded)
end
def rest_client
#client ||= MyRestClient.new(#settings)
end
end
# config/initializers/custom_mailer_delivery_methods.rb
ActionMailer::Base.add_delivery_method :rest_mail, RestMail
# optionally, specify defaults with the optional hash as the last parameter:
ActionMailer::Base.add_delivery_method :rest_mail, RestMail, {url: 'http://mydefaulturl.com'}
# config/environments/application.rb
config.action_mailer.delivery_method = :rest_mail
config.action_mailer.rest_mail_settings = { url: 'https://example.com', ...}
Hope that gets you on the right track! If you find that you created something useful, perhaps you can make a gem of it and share it back with the community :)
I need your views as i don't know is it possible or not.
I want some emails send by my application should 'Mark as Important' so that when end user receive this mail in there Evolution/Outlook they should know the importance of email.
Currently when i marked any email using evolution as 'Mark as Important' it changes the colour of mail subject and other fields to red.
Both other answers are correct, but the thing is, Outlook uses a non-standard header for signaling importance. It's called X-Priority, so you have to include it in your outgoing mail. You can also include "X-MSMail-Priority: High" for older Outlooks.
def notification
mail({
:to => 'email#example.com',
:subject => 'My subject',
:from => 'me#somewhere.com',
'Importance' => 'high',
'X-Priority' => '1'}) do |format|
format.text
format.html
end
end
class Notifier < ActionMailer::Base
default :from => 'no-reply#example.com',
:return_path => 'system#example.com'
def welcome(recipient)
#account = recipient
mail(:to => recipient.email_address_with_name,
:bcc => ["bcc#example.com", "Order Watcher <watcher#example.com>"],
:subject => "No way!",
:importance => "High") # <======
end
end
The MIME RFC lists importance as a header that can be sent with MIME email. The values that can be used are high, normal or low. To send an email with an adjusted importance, use an API that allows you to either set the importance via an API method, or one that allows you to set individual headers (such as TMail).
I don't know Ruby, so I can't give you an example, but hopefully this points you in the right direction.
I want send newsletter to all registered users, but only the last user (in database) receive the mail.
def letter(nletter)
#nletter = nletter
#users=Newsletter.all
#users.each do |users|
mail(:to => users.email, :subject => #nletter.subject)
end
end
Whats wrong?
If the code you showed us is in your Mailer class, it's because the mail method just sets various attributes on a Mail object. When you loop through all your users and call mail for each one, you're just resetting the subject and (more importantly) the recipient on a single Mail object. So when the function finishes and the Mail is sent out, the current recipient is the last user you set it to - the last user in your database.
You can get around this in two different ways. If it's a generic e-mail (everybody gets the same exact message), you can just pass an array of e-mail addresses as :to:
Note: As Josh points out in the comments, you'll pretty much always want to use :bcc instead of :to, so you don't end up broadcasting your entire mailing list.
def letter(nletter)
#nletter = nletter
#users=Newsletter.all
mail(:to => #users.map(&:email), :subject => #nletter.subject)
end
But if each user gets a custom e-mail ("Hi, #{username}!" or somesuch), you'll have to create a new Mail object for each user. You can do this by calling Mailer.deliver_letter(nletter, user) for each user:
# Somewhere outside of your Mailer:
nletter = "...whatever..."
Newsletter.all.each do |user|
Mailer.deliver_letter(nletter, user)
end
# And your mailer function would look like:
def letter(nletter, user)
#nletter = nletter
mail(:to => user.email, :subject => #nletter.subject)
end
Hope this helps!
I saw this post but mine is slightly different:
Rails ActionMailer with multiple SMTP servers
I am allowing the users to send mail using their own SMTP credentials so it actually does come from them.
But they will be sent from the Rails app, so that means for each user I need to send their emails using their own SMTP server.
How can I do that?
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
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)
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 = ..
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
I'm using my Gmail Apps for Domain account to send email within my rails application for standard automated emails (user signup, forgot password, notify admin of new comment, etc), but I'm worried about the 500 emails per day limit set by Google.
Google suggests one way to overcome the limit is to use multiple user accounts.
So, I've setup 10 additional gmail user accounts (noreply1, noreply2, noreply3, etc) - I'd like to track when any of these accounts has sent 500 emails in a 24 hour period and use the idle account accordingly.
How do I dynamically set the :user_name value in ActionMailer::Base.smtp_settings?
Here's my current setup - NOTE: this sends from "noreply1" every time, even though i'm explicitly setting :user_name and :from to "noreply2":
--- development.rb ---
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => "587",
:domain => "mydomain.com",
:authentication => :plain,
:user_name => "noreply1#mydomain.com",
:password => "password"
}
--- account.rb --- (MODEL, called via a callback)
after_create :send_welcome_email
...
def send_welcome_email
#ActionMailer::Base.smtp_settings[:user_name] = 'noreply2#mydomain.com'
ActionMailer::Base.smtp_settings.merge!({:user_name => "noreply2#mydomain.com"})
SubscriptionNotifier.deliver_welcome(self)
end
--- subscription_notifier.rb --- (MODEL)
class SubscriptionNotifier < ActionMailer::Base
def welcome(account)
#sent_on = Time.now
#subject = "Welcome to the App"
#recipients = account.email
#from = "noreply2#mydomain.com"
#body = { :account => account }
end
end
You could also set up an MTA on your server and use that for sending the mail.
That's what we do.
You have to add your server's IP as a valid one for sending email in your domain's SPF record to avoid getting marked as spam.
Another benefit of this is that if you do this, you can set the From: address of the email to be one of your users, which you cannot do with GMail.
Store the available usernames in a table in the database, along with a 'last-modified', 'last-reset' and a sent count. You can then query this when sending an email to find the least used email address currently. Then increment the sent count and last-modified account. The 'last-reset' value can be used for your cleanup code so that you reset the counts each 24 hour period.
This also makes it easy to add new email accounts, retire accounts you aren't using anymore, implement in a different app, etc. as it's all just in a database table that you can change when required.
You should be able to set the :user_name element in the hash in the mailer in the same fashion as in the configuration, namely by doing:
ActionMailer::Base.smtp_settings[:user_name] = 'new_user_name'
Although this may require some extra code to force a reload of any internal action mailer config (not tested this myself)
The comment box was becoming too restrictive for my questions. Changing the ActionMailer::Base.smtp_settings hash dynamically works as expected for me, so I suspect there is some other factor at play here. Some things to try:
Are you using a TLS plugin? I used action_mailer_optional_tls with Rails 2.3.2 and Ruby 1.8.6.
What is being writing to the log/console?
You're changing the username but not the password: do all the noreply accounts have the same password?
Edit: more things to try
I'd have a good look at that smtp_tls.rb file mentioned in the comments to make sure nothing's hard-coded. Or remove it and try the plugin I linked above. To use it, you just need to add :tls => true to the smtp_settings hash.