I have a customer mailer set up with devise as you can see below:
class DeviseMailer < Devise::Mailer
default from: "hello#example.com"
def mandrill_client
#mandrill_client ||= Mandrill::API.new MANDRILL_API_KEY
end
def confirmation_instructions(record, token, opts={})
template_name = "user-confirm-account"
template_content = []
message = {
to: [{email: record.email}],
subject: "Confirm Your account",
merge_vars: [
{rcpt: record.email,
vars: [
{name: "CONFIRM_ACCOUNT_LINK", content: "#{root_url}users/confirmation?confirmation_token=#{token}"},
]
}
]
}
mandrill_client.messages.send_template template_name, template_content, message
end
def reset_password_instructions(record, token, opts={})
template_name = "user-forgot-password"
template_content = []
message = {
to: [{email: record.email}],
subject: "Password Reset",
merge_vars: [
{rcpt: record.email,
vars: [
{name: "PASSWORD_RESET_LINK", content: "#{root_url}users/password/edit?reset_password_token=#{token}"},
]
}
]
}
mandrill_client.messages.send_template template_name, template_content, message
end
def unlock_instructions(record, token, opts={})
# code to be added here later
end
end
This works great. I did this so that I could customise confirmation emails sent by Mandrill. In order to send the confirmation email I call the following:
#user.send_confirmation_instructions
This works but I want to be able to send a different template for confirmation_instructions depending on a parameter I pass to the mailer. Such as source=contactform. How would I include a parameter in my #user.send_confirmation_instructions code and then retrieve it in the mailer? Thanks! :)
Related
I'm working with redmine and I've installed a plugin for managing mails.
When I try to send a mail I obtain the following error
[ActiveJob] [ActionMailer::DeliveryJob] [uuid] Error performing ActionMailer::DeliveryJob (Job ID: uuid) from Async(mailers) in 41.81ms: NoMethodError (undefined method `each' for #<User:id>):
This is the file that gives me the error
module EncryptMails
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :mail_without_relocation, :mail
alias_method :mail, :mail_with_relocation
end
end
module InstanceMethods
# action names to be processed by this plugin
def actions
[
'attachments_added',
'document_added',
'issue_add',
'issue_edit',
'message_posted',
'news_added',
'news_comment_added',
'wiki_content_added',
'wiki_content_updated'
]
end
# dispatched mail method
def mail_with_relocation(headers={}, &block)
# pass unchanged, if action does not match or plugin is inactive
act = Setting.plugin_openpgp['activation']
return mail_without_relocation(headers, &block) if
act == 'none' or not actions.include? #_action_name or
(act == 'project' and not project.try('module_enabled?', 'openpgp'))
# relocate recipients
recipients = relocate_recipients(headers)
header = #_message.header.to_s
# render and deliver encrypted mail
reset(header)
m = mail_without_relocation prepare_headers(
headers, recipients[:encrypted], encrypt = true, sign = true
) do |format|
format.text
end
m.deliver
# render and deliver filtered mail
reset(header)
tpl = #_action_name + '.filtered'
m = mail_without_relocation prepare_headers(
headers, recipients[:filtered], encrypt = false, sign = true
) do |format|
format.text { render tpl }
format.html { render tpl } unless Setting.plain_text_mail?
end
m.deliver
# render unchanged mail (deliverd by calling method)
reset(header)
m = mail_without_relocation prepare_headers(
headers, recipients[:unchanged], encrypt = false, sign = false
) do |format|
format.text
format.html unless Setting.plain_text_mail?
end
m
end
# get project dependent on action and object
def project
case #_action_name
when 'attachments_added'
#attachments.first.project
when 'document_added'
#document.project
when 'issue_add', 'issue_edit'
#issue.project
when 'message_posted'
#message.project
when 'news_added', 'news_comment_added'
#news.project
when 'wiki_content_added', 'wiki_content_updated'
#wiki_content.project
else
nil
end
end
# relocates reciepients (to, cc) of message
def relocate_recipients(headers)
# hash to be returned
recipients = {
:encrypted => {:to => [], :cc => []},
:blocked => {:to => [], :cc => []},
:filtered => {:to => [], :cc => []},
:unchanged => {:to => [], :cc => []},
:lost => {:to => [], :cc => []}
}
# relocation of reciepients
[:to, :cc].each do |field|
headers[field].each do |user|
# encrypted
unless Pgpkey.find_by(user_id: user.id).nil?
recipients[:encrypted][field].push user and next
end
# unencrypted
case Setting.plugin_openpgp['unencrypted_mails']
when 'blocked'
recipients[:blocked][field].push user
when 'filtered'
recipients[:filtered][field].push user
when 'unchanged'
recipients[:unchanged][field].push user
else
recipients[:lost][field].push user
end
end unless headers[field].blank?
end
recipients
end
# resets the mail for sending mails multiple times
def reset(header)
#_mail_was_called = false
#_message = Mail.new
#_message.header header
end
# prepares the headers for different configurations
def prepare_headers(headers, recipients, encrypt, sign)
h = headers.deep_dup
# headers for recipients
h[:to] = recipients[:to]
h[:cc] = recipients[:cc]
# headers for gpg
h[:gpg] = {
encrypt: false,
sign: false
}
# headers for encryption
if encrypt
h[:gpg][:encrypt] = true
# add pgp keys for emails
h[:gpg][:keys] = {}
[:to, :cc].each do |field|
h[field].each do |user|
user_key = Pgpkey.find_by user_id: user.id
unless user_key.nil?
h[:gpg][:keys][user.mail] = user_key.fpr
end
end unless h[field].blank?
end
end
# headers for signature
if sign
server_key = Pgpkey.find_by(:user_id => 0)
unless server_key.nil?
h[:gpg][:sign] = true
h[:gpg][:sign_as] = Setting['mail_from']
h[:gpg][:password] = server_key.secret
end
end
h
end
end
end
The stack of the log tells me that the error is in row 109
# relocation of reciepients
[:to, :cc].each do |field|
I'm not an expert of ruby and rails but I've seen that each is a method of a Ruby array, not a custom one, so I don't understand why I obtain the error.
What I am doing wrong and how can I fix this error?
Are you sure the problem isn't on this line?
h[field].each do |user|
The field there would be :to or :cc so h[field] could be a User instance.
If you want to allow h[:to] or h[:cc] to be a single User or an array of Users, then wrap it in Array():
# relocation of reciepients
[:to, :cc].each do |field|
Array(headers[field]).each do |user|
#^^^^
I'd also move that trailing unless so it doesn't get missed, maybe something like this:
%i[to cc].select { |field| headers[field].present? }.each do |field|
Array(headers[filed]).each do |user|
#...
end
end
I am using mailgun-ruby to send emails in my rails app.
I have activated a number of domains on my Mailgun account and for each ActionMailer I wish to choose a specific domain to send emails from.
The gem's documentation only explains a global way of setting mailgun_settings:
config.action_mailer.delivery_method = :mailgun
config.action_mailer.mailgun_settings = {
api_key: 'api-myapikey',
domain: 'mydomain.com'
}
Any suggestion how this can be done per ActionMailer?
I came up with a self crafted design for this:
class ApplicationMailer < ActionMailer::Base
before_action do
#layout = 'mailer'
#from = 'default#domain.com'
#to = 'default_to#domain.com'
#subject = 'Default Subject'
#domain = 'default.domain.com'
#params = {}
end
after_action do
ac = ActionController::Base.new()
mg = Mailgun::Client.new 'key-xxxxxxxxx'
message_params = {
from: #from,
to: #to,
subject: #subject,
text: ac.render_to_string("#{self.class.to_s.underscore}/#{action_name}.text", layout: #layout, locals: #params),
html: ac.render_to_string("#{self.class.to_s.underscore}/#{action_name}.html", layout: #layout, locals: #params)
}
mg.send_message #domain, message_params
end
end
class UserMailer < ApplicationMailer
before_action do
#from = 'Domain <updates#domain.com>'
#domain = 'updates.domain.com'
end
def test
#to = "yourself#gmail.com"
#subject = "Test"
#params = {}
end
end
Customize user_mailer/test.txt.erb and user_mailer/test.html.erb and send the email:
UserMailer.test
I thought I was getting closer to wrapping my head around Rails until this challenge. I have an initializer agilecrm.rb - content show below. I am using AgileCRM Ruby code to try and connect my app with AgileCRM system. When using the code below, with the test Create Contact array at the bottom, it successfully creates a contact in my AgileCRM account, so I know at least this part works. What I need to do is create a new AgileCRM user every time I create a new Devise user. I have a feeling that I am looking at this the wrong way and probably need a controller for this, but this is not completely foreign to me, but I still can't figure out when way to go. Thank you.
config/initializers/agilecrm.rb
require 'net/http'
require 'uri'
require 'json'
class AgileCRM
class << self
def api_key=(key)
##api_key = key
end
def domain=(d)
##domain = d
end
def email=(email)
##email = email
end
def api_key
##api_key
end
def domain
##domain
end
def email
##email
end
def request(method, subject, data = {})
path = "/dev/api/#{subject}"
case method
when :get
request = Net::HTTP::Get.new(path)
when :post
request = Net::HTTP::Post.new(path)
request.body = data.to_json
when :put
request = Net::HTTP::Put.new(path)
request.body = data.to_json
when :delete
request = Net::HTTP::Delete.new(path)
else
raise "Unknown method: #{method}"
end
uri = URI.parse("https://#{domain}.agilecrm.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request['Content-Type'] = 'application/json'
request['Accept'] = 'application/json'
request.basic_auth AgileCRM.email, AgileCRM.api_key
response = http.request(request)
response.body
end
end
end
AgileCRM.api_key = '*******'
AgileCRM.domain = '*******'
AgileCRM.email = '*******'
# ======================Create Contact====================================
contact_data = '{
"star_value": "4",
"lead_score": "92",
"tags": [
"Lead",
"Likely Buyer"
],
"properties": [
{
"type": "SYSTEM",
"name": "first_name",
"value": "John"
}
]
}'
parsed_contact_data = JSON.parse(contact_data)
print(AgileCRM.request :post, 'contacts', parsed_contact_data)
You might want to move this logic into your User model, and have a after_save hook to push data to agilecrm. Assuming that the Devise user model is called User :
class User < ApplicationRecord
...
after_save :sync_to_agilecrm
def sync_to_agilecrm
# your agilecrm api calls go here
...
end
end
The above should do what you are trying to achieve.
I am trying to set up the reset password emails for devise but my project uses amazon not the default mailer in ruby. How can i go about changing this?
Thanks!
UPDATE
I have connected the AmazonMailer using config.mailer = "AmazonMailer" now this is what my mailer looks like
class AmazonMailer < 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 your mailer uses the devise views
# require 'sendgrid-ruby'
# include SendGrid
# def send_email(subject, body, to_email, from_email)
# from = Email.new(email: "#{from_email}")
# to = Email.new(email: "#{to_email}")
# content = Content.new(type: 'text/html', value: "#{body}")
# mail = Mail.new(from, subject, to, content)
# personalization = Personalization.new
# personalization.to = to
# #personalization.custom_args = CustomArg.new(key: obj_type, value: obj_id)
# mail.personalizations = personalization
# puts mail.to_json
# sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'] || '[EXPOSED API KEY]', host: 'https://api.sendgrid.com')
# response = sg.client.mail._('send').post(request_body: mail.to_json)
# puts response.status_code
# puts response.body
# puts response.headers
# end
require 'aws-sdk'
require 'json'
# Overrides same inside Devise::Mailer
def reset_password_instructions(record, token, opts={})
end
def self.send_email(subject, body, from_name, from_email, to_email, source)
client = Aws::SES::Client.new
resp = client.send_email({
destination: {
bcc_addresses: [],
cc_addresses: [],
to_addresses: [to_email]
},
message: {
body: {
html: {
charset: "UTF-8",
data: body
},
text: {
charset: "UTF-8",
data: ""
}
},
subject: {
charset: "UTF-8",
data: subject
}
},
reply_to_addresses: [from_email],
#return_path: "",
#return_path_arn: "",
source: source,
#source_arn: ""
})
resp['message_id'] unless !resp && !resp['message_id']
end
end
inside my mailer I would like to override the reset_password_instructions method to send from Amazon and not the default.
Why is it that this method produces an empty variable and therefore empty body?
custom_email.text.erb
<%=#message%>
user_mailer.rb
default from: "Name <name#domain.com>"
def custom_email(email, subject, message)
mail to: email, subject: "Name || #{subject}"
#message = message
end
While this method works:
mail to: email, subject: "Name || #{subject}", body: message
write this
default from: "Name <name#domain.com>"
def custom_email(email, subject, message)
#message = message
mail to: email, subject: "Name || #{subject}"
end
instead of
default from: "Name <name#domain.com>"
def custom_email(email, subject, message)
mail to: email, subject: "Name || #{subject}"
#message = message
end
then it will consider #message