Ok I have seen many discussions about customizing devise email subject but none seems to solve what I want. Currently my confirmation email subject reads "Confirm your Qitch.com account". I want to customize this email subject and add a dynamic value of a user's name in it such that if user ALEX signs up for an account, he should get an email address with the subject, Welcome ALEX, confirm your Qitch.com account. How can I achieve this in devise?
devise.en.yml
mailer:
confirmation_instructions:
subject: 'Confirm your Qitch.com account'
reset_password_instructions:
subject: 'Reset your Qitch.com password'
unlock_instructions:
subject: 'Unlock your Qitch.com account'
Lastly, how do I add a name in the reply address or from address, currently when you receive the mail, it says sender: no-reply#qitch.com Is there a way I can customize it to Qitch
Thanks
I see that no answers are clean enough so I would like to make a short summary here.
First of all, you have to tell Devise you're going to override its origin mailer methods by:
config/initializers/devise.rb
config.mailer = 'MyOverriddenMailer'
After that, you need to create your overridden mailer class and override whatever method you want like this:
app/mailers/my_overridden_mailer.rb
class MyOverriddenMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
default template_path: 'devise/mailer' # to make sure that you mailer uses the devise views
def confirmation_instructions(record, token, opts={})
if record.name.present?
opts[:subject] = "Welcome #{record.name}, confirm your Qitch.com account"
else
opts[:subject] = "Confirm your Qitch.com account"
end
super
end
end
Remember to restart your Rails server to apply the changes! :)
Note:
List of opts options: subject, to, from, reply_to, template_path, template_name.
record is the instance of User model
And of course, origin document
Devise helper here and How To: Use custom mailer
class MyMailer < Devise::Mailer
def confirmation_instructions(record, opts={})
headers = {
:subject => "Welcome #{resource.name}, confirm your Qitch.com account"
}
super
end
def reset_password_instructions(record, opts={})
headers = {
:subject => "Welcome #{resource.name}, reset your Qitch.com password"
}
super
end
def unlock_instructions(record, opts={})
headers = {
:subject => "Welcome #{resource.name}, unlock your Qitch.com account"
}
super
end
end
Or
class MyMailer < Devise::Mailer
...
...
private
def headers_for(action)
if action == :confirmation_instructions
headers = {
:subject => "Welcome #{resource.name}, confirm your Qitch.com account"
}
elsif action == :reset_password_instructions
headers = {
:subject => "Welcome #{resource.name}, reset your Qitch.com password"
}
else
headers = {
:subject => "Welcome #{resource.name}, unlock your Qitch.com account"
}
end
end
end
And tell devise to use your mailer:
#config/initializers/devise.rb
config.mailer = "MyMailer"
NOTE : I haven't tried them yet, but they may be helpful and for anyone, please correction my answer, if there is an error you could edit my answer
I'm working with devise (3.2.1) and I've implemented the following solution, but to modify the from: field with localization:
# app/mailers/devise_mailer.rb
class DeviseMailer < Devise::Mailer
def confirmation_instructions(record, token, opts={})
custom_options(opts)
super
end
def reset_password_instructions(record, token, opts={})
custom_options(opts)
super
end
def unlock_instructions(record, token, opts={})
custom_options(opts)
super
end
private
def custom_options(opts)
opts[:from] = I18n.t('devise.mailer.from', name: Tenancy.current_tenancy.name, mail: ENV['FROM_MAILER'] )
end
end
Then I've defined the message in my locale files
# config/locales/devise.es.yml
es:
devise:
mailer:
from: "Portal de trabajo %{name} <%{mail}>"
To modify the subject, it should be almost the same:
def confirmation_instructions(record, token, opts={})
custom_options(opts, :confirmation_instructions)
super
end
private
def custom_options(opts, key)
opts[:from] = I18n.t('subject', scope: [:devise, :mailer, key])
end
# and in your locale file
es:
devise:
mailer:
confirmation_instructions:
subject: Instrucciones de confirmaciĆ³n
Hook in headers_for to e.g. prefix the subject for all devise mails.
# config/initializers/devise.rb
Devise.setup do |config|
# ...
config.mailer = 'DeviseMailer'
# ...
end
# app/mailers/devise_mailer.rb
class DeviseMailer < Devise::Mailer
def headers_for(action, opts)
super.merge!({ subject: 'Hi ALEX! ' + subject_for(action) })
end
end
Yo should create an ActionMailer like this one:
class Sender < ActionMailer::Base
default :from => "'Eventer' <dfghjk#gmail.com>"
def send_recover(user, pw)
mail(:to => user.email , :subject => "You have requested to change your password from Eventer") do |format|
format.text {
render :text =>"Dear #{user.name},
**Body**
Regards."
}
end
end
end
Then you should call it from the controller this way:
Sender.send_recover(#mail, current_user, #meetup).deliver
I hope it works for you!
Regards
Related
I have added the devise_invitable gem and a custom mailer. It works and normal devise emails (eg. confirmation_instructions) are reading the i18n file correctly, but invitation_instructions is not.
Here is the devise.en.yml:
en:
devise:
mailer:
confirmation_instructions:
subject: "Hi %{first_name}, please confirm your email to activate your account"
invitation_instructions:
subject: "%{first_name} has invited you to join their team!"
hello: "Oi"
someone_invited_you: "Pig"
The custom mailer class:
class CustomDeviseMailer < Devise::Mailer
def confirmation_instructions(record, token, opts={})
custom_options(record, opts, :confirmation_instructions)
super
end
def invitation_instructions(record, token, opts={})
custom_options(record, opts, :invitation_instructions)
super
end
private
def custom_options(record, opts, key)
opts[:subject] = I18n.t('subject', scope: [:devise, :mailer, key], first_name: record.first_name)
end
end
If I change the invitation_instructions method to this:
def invitation_instructions(record, token, opts={})
custom_options(record, opts, :invitation_instructions)
opts[:subject] = "TEST"
super
end
then the invitation email subject correctly changes to 'TEST'.
So why is it not reading the i18n file?
NOTE
I also generated the default invitation view and that is also not reading the i18n file. For example the first line of the default view is:
\app\views\devise\mailer\invitation_instructions.html.erb
<p>
<%= t("devise.mailer.invitation_instructions.hello", email: #resource.email) %>
</p>
Which should render 'Oi' from the i18n file, but it renders the default 'Hello' instead.
It turns out that the devise_invitable gem does not read devise.en.yml because it creates its OWN locale file:
devise_invitable.en.yml
and so that is where I need to make the text customisations.
I'm trying to make an app in Rails 4.
For the past 3 years, I've been struggling to figure out devise/omniauth (I am still trying to get it to work).
Stepping aside from the main problems while I try and find the will to live through this, I've tried to setup emails with Mandrill.
I found this tutorial, which I am trying to follow along: https://nvisium.com/blog/2014/10/08/mandrill-devise-and-mailchimp-templates/
I have a mailer called mandrill_devise_mailer.rb
class MandrillDeviseMailer < Devise::Mailer
def confirmation_instructions(record, token, opts={})
# code to be added here later
end
def reset_password_instructions(record, token, opts={})
options = {
:subject => "Reset your password",
:email => record.email,
:global_merge_vars => [
{
name: "password_reset_link",
# content: "http://www.example.com/users/password/edit?reset_password_token=#{token}"
content: "http://www.cr.com/users/password/edit?reset_password_token=#{token}"
},
{
name: "PASSWORD_RESET_REQUEST_FROM",
content: record.full_name
}
],
:template => "Forgot Password"
}
mandrill_send options
end
def unlock_instructions(record, token, opts={})
# code to be added here later
end
def mandrill_send(opts={})
message = {
:subject=> "#{opts[:subject]}",
:from_name=> "Reset Instructions",
# :from_email=>"example#somecorp.com",
:from_email=>["PROD_WELCOME"],
:to=>
[{"name"=>"#{opts[:full_name]}",
"email"=>"#{opts[:email]}",
"type"=>"to"}],
:global_merge_vars => opts[:global_merge_vars]
}
sending = MANDRILL.messages.send_template opts[:template], [], message
rescue Mandrill::Error => e
Rails.logger.debug("#{e.class}: #{e.message}")
raise
end
end
The differences between the above and what they have done in the tutorial are:
In my mail chimp mandrill template, I have:
Change my password
When I receive the email to reset the instructions, I get an underlined link to the change password form, which says 'change my password next to it. I want 'change my password to be the label which conceals the link text'.
Can anyone see what I've done wrong?
Here is how I created custom DeviseMailer
class MyDeviseMailer < Devise::Mailer
default template_path: 'devise/mailer' # to make sure that your mailer uses the devise views
def reset_password_instructions(record, token, opts={})
opts['from_email'] = "donotreply#mywebsite.com"
opts['from_name'] = "Password Reset"
#Rails.logger.mail.info "reset_password_instructions #{record.to_json} \n #{token.to_json} \n #{opts.to_json}"
super
end
end
https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer and
Add dynamic value in devise email subject
Is it possible to write mailer methods with define_method,because i need almost similar methods,like
notify_user_approved & notify_user_rejected
%w(approved rejected).each do|meth|
define_method("notify_user_#{meth}") do |user,subject|
#url = user.email
#user = user
mail(to: #url, subject: subject)
end
end
Notification is my mailer class name
Notification.notify_user_rejected(User.last,'approved').deliver_now
i having NoMethodError: undefined methodmail' for Notification:Class
when to try run my mailer
whole class
class Notification < ActionMailer::Base
%w(approved rejected).each do|meth|
define_method("notify_user_#{meth}") do |user,subject|
#url = user.email
#user = user
mail(to: #url, subject: subject)
end
end
end
I would like the invitations for my app to come from the inviter instead of a system email address. How can I override the config.mailer_sender from devise.rb?
I have this in my mailer and have confirmed that it is getting called, but it does not override the :from. Note: it is a private method, I tried it as a public method with no effect.
private
def headers_for(action)
if action == :invitation_instructions
headers = {
:subject => "#{resource.invited_by.full_name} has invited you to join iTourSmart",
:from => resource.invited_by.email,
:to => resource.email,
:template_path => template_paths
}
else
headers = {
:from => mailer_sender(devise_mapping),
:to => resource.email,
:template_path => template_paths
}
end
if resource.respond_to?(:headers_for)
headers.merge!(resource.headers_for(action))
end
unless headers.key?(:reply_to)
headers[:reply_to] = headers[:from]
end
headers
end
The better solution without any hacks/monkey patches will be:
for example, in your model:
def invite_and_notificate_member user_email
member = User.invite!({ email: user_email }, self.account_user) do |u|
u.skip_invitation = true
end
notificate_by_invitation!(member)
end
def notificate_by_invitation! member
UserMailer.invited_user_instructions(member, self.account_user, self.name).deliver
end
In the mailer:
def invited_user_instructions(user, current_user, sa)
#user = user
#current_user = current_user
#sa = sa
mail(to: user.email, subject: "#{current_user.name} (#{current_user.email}) has invited you to the #{sa} account ")
end
So you can put any subject/data in the body of the mail.
Good luck!
Look at my answer to a similar question, it might help.
Edit: so it seems that you need to define a public headers_for method in your resource class.
Solution: Put some version of this method in User.rb, make sure it's public.
def headers_for(action)
action_string = action.to_s
case action_string
when "invitation" || "invitation_instructions"
{:from => 'foo#bar.com'}
else
{}
end
end
You have to return a hash in because Devise::Mailer will try to merge the hash values.
Take a look at devise_invitable wiki.
class User < ActiveRecord::Base
#... regular implementation ...
# This method is called interally during the Devise invitation process. We are
# using it to allow for a custom email subject. These options get merged into the
# internal devise_invitable options. Tread Carefully.
#
def headers_for(action)
return {} unless invited_by && action == :invitation_instructions
{ subject: "#{invited_by.full_name} has given you access to their account" }
end
end
When I click on the link in my confirmation email that devise sends, it seems to go to a path that is not recognized by my application.
The url looks something like this:
http://glowing-flower-855.heroku.com/users/confirmation?confirmation_token=lIUuOINyxfTW3TBPPI
which looks correct, but it seems to go to my 500.html file.
It has something to do with this code in my user model that overrides Devise's confirm! method:
def confirm!
UserMailer.welcome_message(self).deliver
super
end
According to my logs, this is the error:
2011-06-10T03:48:11+00:00 app[web.1]: ArgumentError (A sender (Return-Path, Sender or From) required to send a message):
2011-06-10T03:48:11+00:00 app[web.1]: app/models/user.rb:52:in `confirm!'
which points to this line: UserMailer.welcome_message(self).deliver
Here's my user mailer class:
class UserMailer < ActionMailer::Base
def welcome_message(user)
#user = user
mail(:to => user.email, :subject => "Welcome to DreamStill")
end
end
You are missing the "from:" value, it's a must for SMTP handling:
class UserMailer < ActionMailer::Base
# Option 1
#default_from "bob#dylan.com"
def welcome_message(user)
#user = user
mail(
# Option 2
:from => "paul#mccarthy.com",
:to => user.email,
:subject => "Welcome to DreamStill"
)
end
end