ActionMailer Observer not working - ruby-on-rails

I defined an ActionMailer Observer and it's not being called. How can I go about troubleshooting this? Rails 3.1.3, Ruby 1.9.2. Alternatively, I want a method called whenever an email is sent form a certain ActionMailer subclass. This is the only clean way I could find to implement this (I could call a method from each mailing method in the ActionMailer subclass, but that's not very DRY). Any other suggestions as to how to accomplish this would be welcome.
config/initializers/mail_observer.rb:
class MailObserver
def self.delivered_email(message)
require 'ruby-debug' ; debugger
user = User.find_by_email(message.to[0])
if user
email_type = caller[1]
UserMailerLogging.create!(user_id: #user.id, email_type: email_type, contents: self.body)
end
end
end
ActionMailer::Base.register_observer(MailObserver)
app/mailers/user_mailer:
class UserMailer < ActionMailer::Base
default from: "no-reply#testing.com"
...
def unfinished_setup(user)
#user = user
mail to: user_email(user), subject: "Testing..."
end
...
end
And, in the Rails Console:
irb(main):001:0> UserMailer.unfinished_setup(User.find(1))
=> #<Mail::Message:70192154395900, Multipart: false, Headers: <From: no-reply#testing.com>, <To: Test User<user#testing.com>>, <Subject: Testing...>, <Mime-Version: 1.0>, <Content-Type: text/plain>>

I believe the observer won't fire until you actually deliver the message. Your code in the rails console is only creating the email, not sending it. Adding .deliver to the end should deliver the message and execute the observer code.

Related

Where to put ruby helpers Sendgrid V3 Send API

I am trying to integrate Sendgrid using their Github documentation.
In their examples they suggest that you create a Mail Helper class but give very little guidance on how to actually do this.
I have a scheduled Rake task running using Heroku Scheduler that I would like to send an email when the task is complete and was hoping to use Sendgrid for this.
Currently I have the following code in /lib/tasks/scheduler.rake
require 'sendgrid-ruby'
include SendGrid
desc "Testing Email Rake"
task :test_sendgrid => :environment do
puts 'Starting Sendgrid Email Test'
send_task_complete_email()
puts 'Sendgrid Email Test Complete'
end
def send_task_complete_email
from = Email.new(email: 'test#example.com')
to = Email.new(email: 'test#example.com')
subject = 'Sending with SendGrid is Fun'
content = Content.new(type: 'text/plain', value: 'and easy to do anywhere, even with Ruby')
mail = Mail.new(from, subject, to, content)
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
response = sg.client.mail._('send').post(request_body: mail.to_json)
puts response.status_code
puts response.body
puts response.headers
end
I don't have the helper classes added anywhere as I am not sure which bits to add or where to put them. At the moment when I run this task I receive a 400 Bad request error back from Sendgrid and I believe it's because I don't have these helpers in place.
Any advice to fix this would be much appreciated as when I try to integrate without using the helpers and instead writing out the JSON I can successfully send the email but receive a TypeError: Mail is not a module when I try to deploy to Heroku.
UPDATE: ERROR RECEIVED USING ANSWER BELOW
400
{"errors":[{"message":"Invalid type. Expected: object, given: string.","field":"(root)","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Request-Body-Parameters"}]}
{"server"=>["nginx"], "date"=>["Thu, 07 Jun 2018 09:02:42 GMT"], "content-type"=>["application/json"], "content-length"=>["191"], "connection"=>["close"], "access-control-allow-origin"=>["https://sendgrid.api-docs.io"], "access-control-allow-methods"=>["POST"], "access-control-allow-headers"=>["Authorization, Content-Type, On-behalf-of, x-sg-elas-acl"], "access-control-max-age"=>["600"], "x-no-cors-reason"=>["https://sendgrid.com/docs/Classroom/Basics/API/cors.html"]}
You need to use Action Mailer:
First create a mailer class to add your mail details (i.e. UserMailer):
$ bin/rails generate mailer UserMailer
it will create the following files:
create app/mailers/user_mailer.rb
create app/mailers/application_mailer.rb
invoke erb
create app/views/user_mailer
create app/views/layouts/mailer.text.erb
create app/views/layouts/mailer.html.erb
invoke test_unit
create test/mailers/user_mailer_test.rb
create test/mailers/previews/user_mailer_preview.rb
Now edit the file app/mailers/user_mailer.rb:
require 'sendgrid-ruby'
include SendGrid
class UserMailer < ApplicationMailer
def send_task_complete_email
from = Email.new(email: 'test#example.com')
to = Email.new(email: 'test#example.com')
subject = 'Sending with SendGrid is Fun'
content = Content.new(type: 'text/plain', value: 'and easy to do anywhere, even with Ruby')
mail = Mail.new(from, subject, to, content)
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
response = sg.client.mail._('send').post(request_body: mail.to_json)
puts response.status_code
puts response.body
puts response.headers
end
end
Then you can simply send emails using this code:
UserMailer.send_task_complete_email.deliver_now
Or from rake task:
desc "Testing Email Rake"
task :test_sendgrid => :environment do
puts 'Starting Sendgrid Email Test'
UserMailer.send_task_complete_email.deliver_now
puts 'Sendgrid Email Test Complete'
end
Update:
Because there is Mail module in Rails, you need to specify the correct SendGrid Mail module by changing:
mail = Mail.new(from, subject, to, content)
to
mail = SendGrid::Mail.new(from, subject, to, content)

Sendgird transactional email and template with Ruby on Rails

This is a Rails 5 app, and I am using the smtpapi gem. In my controller I am calling:
NewsletterSignupMailer.send_signup_email(email_address).deliver_now
and in app/mailers/newsletter_signup_mailer I have...
class NewsletterSignupMailer < ApplicationMailer
default from: 'mark#remotegig.io'
def send_signup_email(email_address)
#email = email_address
headers "X-SMTPAPI" => {
to: #email,
filters: {
templates: {
settings: {
enable: 1,
template_id: "7d783012-5044-4a9b-9875-6f3453r3c20"
}
}
}
}.to_json
end
end
In config/environment.rb I have ActionMailer::Base.smtp_settings configured with my sendgrid username and password. When I call the mailer I don't get any emails, but no errors in the rails console, only:
NewsletterSignupMailer#send_signup_email: processed outbound mail in 0.2ms
...so not sure how to trouble shoot this, or event see what the response from sendgrid is.

ActionMailer::Base::NullMail when trying exception_notification in development

I'd like to add the exception_notification gem to our app, however, this happens when I try to manually trigger a mail:
exception
# => #<ZeroDivisionError: divided by 0>
ExceptionNotifier::Notifier.exception_notification(request.env, exception)
# => #<ActionMailer::Base::NullMail:0x007fa81bc7c610>
ExceptionNotifier::Notifier.background_exception_notification(exception)
# => #<ActionMailer::Base::NullMail:0x007fa81bf58190>
In the above example, the console is at a breakpoint inside rescue_from Exception in the ApplicationController after a deliberate 1/0 in some controller.
I'm using delayed_job as well, but - no surprise - ExceptionNotifier::Notifier.background_exception_notification(exception).deliver does not spool anything.
I've already set config.consider_all_requests_local = false in development, but still exception_notification instantiates NullMail. In other parts of the app, mailers work just fine and use sendmail.
Any ideas what I'm doing wrong here? Thanks for your help!
Likely you are using an old version of the ExceptionNotifier and a newer version of ActiveMailer::Base. Not calling the mail command within the email functionality will result in the ActionMailer::Base::NullMail instance returned rather than a Mail instance.
From documentation:
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>"])
end
end
I had my tests / rspec returning NullMail objects. the solution was simple, my code was:
def my_mail(foo)
mail(
to: to,
from: from,
subject: #sample_item.campaign_market.campaign.translation_for(language_id, 'sample_item_mailer.request_review.subject'),
content_type: "text/html"
)
#sample_item.update_attributes!({feedback_requested: true, review_requested_at: Time.now})
TrackingService::Event.new(#user, #user.market, 'sample_items', "request_review_email #{#sample_item.id}").call()
end
what's not immediately clear from the ruby docs is that you need to return the mail function,not just execute it. If you need to do something after building the mail object make sure you return the mail at the end. like so:
def my_mail(foo)
m = mail(
to: to,
from: from,
subject: #sample_item.campaign_market.campaign.translation_for(language_id, 'sample_item_mailer.request_review.subject'),
content_type: "text/html"
)
#sample_item.update_attributes!({feedback_requested: true, review_requested_at: Time.now})
TrackingService::Event.new(#user, #user.market, 'sample_items', "request_review_email #{#sample_item.id}").call()
return m
end

ActionMailer 3 error - undefined method `encode!' for "Welcome":String

I'm getting this error while sending mail to the registered user in rails 3:
undefined method 'encode!' for "Welcome":String
I have the following code
#content = content
mail(:to => content[:email], :subject => "test")
If there is a subject then above error message displaying, if I remove the subject content
#content = content
mail(:to => content[:email], :subject => "") no error message sending with out subject
I'm using:
Rails version 3.0.1
action mailer 3.0.1
mail gem checks for Encoded global constant. If its defined by any gem or your code then it calls encode! on the mail object. Here is this call from UnstructuredField mail gem class:
def encode(value)
value.encode!(charset) if defined?(Encoding) && charset
(value.not_ascii_only? ? [value].pack("M").gsub("=\n", '') : value).gsub("\r", "=0D").gsub("\n", "=0A")
end
For me it was mail subject, a String, so I monkey patched String:
class String
def encode!(value)
#Do any encoding or simply return it
value
end
end
Try using ruby version 1.9
I got this error while using devise with rails 3.0.3 and ruby 1.8.7.
I migrated to ruby 1.9 and it worked like a charm.

Locale not working when called from a rake task

I have a Rails app (2.3.8) where I send emails using ActionMailer from my Controllers, with no problems.
However, I´ve created a rake task to be called from a Cronjob (in Heroku). When those emails are sent, no locale transformations in my dates are made.
I´ve googled to find any kind of solution, but couldn´t.
Anyone can help me?
Thanks.
Here is the code:
cron.rake:
desc 'This task is called by the Heroku cron add-on'
task :cron => :environment do
puts 'Sending diary...'
hollydays = [6,0] #weekend
unless hollydays.member?(Time.zone.now.wday) #if is NOT a weekend
User.all.each do |user|
user.deliver_task_diary
end
end
puts 'done.'
end
user model method:
def deliver_task_diary
TaskMailer.deliver_task_diary(self)
end
the method in TaskMailer model:
def task_diary(user)
next_five_tasks = user.next_five_tasks
last_five_tasks = user.last_five_tasks
recipients "#{user.name} <#{user.email}>"
from "My site <no_reply#mysite.com>"
subject "Your daily tasks."
sent_on Time.zone.now
body :user => user, :next_five_tasks => next_five_tasks, :last_five_tasks => last_five_tasks
end
part of my email template that doesn´t locale:
<%=l task.estimated_delivery_date, :format => :short %>
Solved.
I don´t know if it´s the best way, but I´ve just declared the locale at the very beging of the email html template:
<% I18n.locale = "pt-BR" %>

Resources