Sendgird transactional email and template with Ruby on Rails - 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.

Related

How to preview email using AWS SES (aws-sdk-ses) in Rails application

I am working on Ruby on Rails applications. We choose the AWS SES service to send emails to our users. We are using the aws-sdk-ses gem for this purpose.
And I'm faced with a problem with previewing emails.
My user_mailer.rb has the next code:
# frozen_string_literal: true
class UserMailer < ApplicationMailer
layout 'mailer'
def invite
invitation = params[:invitation]
email = invitation.email
subject = 'Invitation email'
# The HTML body of the email
htmlbody = render_to_string(
template: 'user_mailer/invite',
layout: true,
locals: {
email: receiver_email,
}
)
send_email(
receiver: receiver_email,
sender: 'default#email.com',
subject: subject,
body: htmlbody
)
end
def send_email(receiver:, sender:, subject:, body:)
AWS_SES_CLIENT.send_email(
{
destination: { to_addresses: [receiver] },
message: {
body: {
html: { charset: 'UTF-8',
data: body }
},
subject: {
charset: 'UTF-8',
data: subject
}
},
source: sender
}
)
rescue Aws::SES::Errors::ServiceError => e
Rails.logger.info "ERROR! Email for #{receiver} with subject #{subject} wasn't sent with error message: #{e}"
end
end
And my spec/mailers/preview/user_mailer_preview.rb has the next code:
# frozen_string_literal: true
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview
def invite
UserMailer.with(invitation: UserInvitation.first).invite
end
end
But when I go to the http://localhost:3000/rails/mailers/user_mailer I see the message
You are trying to preview an email that does not have any content.
This is probably because the mail method has not been called in
user_mailer#invite.
I suggest that standard Rails previewer track the calling the mail method, but I'm used custom send_email method to send email. So it doesn't work. I'm trying to find the solution on the AWS SDK guide but I didn't. I suppose it needs to reconfigure action_mailer in some way.

NoMethodError Ruby 1.9.3

I am using Ruby 1.9.3 and getting the following error on the following line while trying to use the SendGrid API.
ERROR [on this line below "mailer.mail(mail_defaults)"]:
NoMethodError (undefined method `to_h' for #<Hash:0x00000005da0958>):
CODE:
assuming some users
recipients = []
recipient = SendGrid::Recipient.new('jn#geo.com')
recipient.add_substitution('name', 'Billy Bob')
recipient.add_substitution('number', 1234)
recipient.add_substitution('time', '10:30pm')
recipients << recipient
# then initialize a template
template = SendGrid::Template.new('blahblah7bef2-d25b00')
# create the client
# see client above
# set some defaults
mail_defaults = {
:from => 'no-reply#geo.com',
:html => '<h1>I like email tests</h1>',
:text => 'I like email tests',
:subject =>'Test Email is great',
}
mailer = SendGrid::TemplateMailer.new(client, template, recipients)
# then mail the whole thing at once
mailer.mail(mail_defaults)
I thought it might be my mail_defaults array so I tried this (see below) and received the same error on the same line.
mail_defaults = {
from: 'no-reply#geo.com',
html: '<h1>I like email tests</h1>',
text: 'I like email tests',
subject: 'Test Email is great',
}
Do I have an error in my code or is their an error in SendGrids mailer.mail method?
This problem is with mail.mailer. This uses the to_h method internally, which was implemented in Ruby 2.1. Effectively, the sendgrid sdk requires ruby 2.1 now. I had the same issue with Ruby 1.9.3 and solved it by upgrading to 2.1.
This is what I used to upgrade to Ruby 2.1 on CentOS 6 (not my gist):
https://gist.github.com/mustafaturan/8290150
Hope this helps.

Response from SMTP server with Rails

How could I get the response from an SMTP server in Ruby on Rails using ActionMailer, when I send an email with the Mailer.deliver method?
I found the Actionmailer SMTP Server Response answer but it doesn't work... Any idea?
I need it because AWS SES return a message ID through, and it's the only way to get the message linked to a bounce or spam report they provide after.
if you get the smtp in way like this
response = Mail.your_mail().deliver
and it isn't getting the response that you need, try deliver_now!
response = Mail.your_mail().deliver_now!
pp response.message
This will show you the result: 250 2.0.0 Ok: queued as 3lG8S16Khmz6ZhXq
I also configured the smtp settings on my Mail.rb
delivery_options = { user_name: 'email#server.com.br',
password: 'mypassword',
authentication: :login,
address: 'smtp.mycompany.com.br',
port: 2525,
domain: 'mycompany.com.br',
return_response: true
}
If using gem "aws-ses" you can get the message id with:
response = your_mailer.send(notification, self, *args).deliver_now!
response.message_id # => "010601531c886c55-6c2f30fc-4237-4294-9029-b60b2d44a691-000000#email.amazonses.com"
For me deliver, deliver_now and deliver_now! work in the same way
EXTRA:
If for some chance you are using devise you can get the ID too:
#[app/model/user.rb]
class User < ActiveRecord::Base
...
# Override send_devise_notification stated in devise/REAMDE.txt
def send_devise_notification(notification, *args)
response = devise_mailer.send(notification, self, *args).deliver_now
response.message_id #=> "010601531c8-86c...000000#email.amazonses.com"
end
...
end

ActionMailer Observer not working

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.

ActionMailer rendering view not sending mail

I am having a weird issue with ActionMailer. It is sending some mails but not others. We recently upgraded to 3.2.12 and that is when the trouble started.
Here is my config:
# Disable delivery errors, bad email addresses will be ignored
config.action_mailer.raise_delivery_errors = true
# config.action_mailer.perform_deliveries = false
config.action_mailer.default_url_options = { :host => "ruby.ourdomain.com/app" }
config.action_mailer.asset_host = "http://ruby.ourdomain.com/app"
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "pop.ourdomain.com"
}
This mailer WORKS:
in the model:
def alertStudent
AbsenceMailer.StudentAbsenceAlert(self).deliver
end
the mailer:
def StudentAbsenceAlert(alert)
#alert = alert
#student = studentInfo(#alert.student_id)
#advisor = staffInfo(#alert.advisor)
#instructor = #alert.polling.instructor
studentAddr = #student['STUDENT_EMAIL']
mail to: studentAddr, cc: #advisor['STAFF_EMAIL'], from: #advisor['STAFF_EMAIL'], subject: "[#{#alert.polling.course}] You have been marked absent #{Time.now.strftime('%m-%e-%Y')}"
end
This mailer DOES NOT WORK and raises NO ERRORS:
the model:
def self.advisorDigest
AbsenceAlert.current_status('active').advisor_day.group_by{|r| r.advisor }.each do |id, alerts|
AbsenceMailer.AdvisorAbsenceDigest(id, alerts).deliver
end
end
the mailer:
def AdvisorAbsenceDigest(id, alerts)
#alerts = alerts
#staff = staffInfo(id)
mail to: #staff['STAFF_EMAIL'], subject: "Student Absence Report #{Time.now.strftime('%m-%e-%Y')}"
puts "[#{Time.now.strftime('%c')}] Sent Advisor Digest: #{alerts.count} alerts to #{#staff['STAFF_EMAIL']}"
end
In the log I see the following
Rendered absence_mailer/AdvisorAbsenceDigest.html.haml within layouts/app (31.6ms)
however it does not actually send the mail.
For a successful call I usually see
Sent mail to email#ourdomain.com (193ms)
immediately following the view render, and I am not getting that in the case where I am seeing a failure.
I have enabled delivery errors, and receive no errors. Our app has not changed, our config has not changed. The only thing we did was upgrade to rails 3.2.12 and the second mailer has begun to fail.
Still unsure why one was working and another wasn't, but I was able to rectify the issue by moving .deliver out of the model and into the mailer itself, such as this:
the model:
def self.advisorDigest
AbsenceAlert.current_status('active').advisor_day.group_by{|r| r.advisor }.each do |id, alerts|
AbsenceMailer.AdvisorAbsenceDigest(id, alerts)
end
end
the mailer:
def AdvisorAbsenceDigest(id, alerts)
#alerts = alerts
#staff = staffInfo(id)
mail(to: #staff['STAFF_EMAIL'], subject: "Student Absence Report #{Time.now.strftime('%m-%e-%Y')}").deliver
puts "[#{Time.now.strftime('%c')}] Sent Advisor Digest: #{alerts.count} alerts to #{#staff['STAFF_EMAIL']}"
end

Resources