Emails with SendGrid Web API in Rails - ruby-on-rails

I'm following this tutorial: https://github.com/sendgrid/sendgrid-ruby/. Very straightforward. However, I want to avoid having a big chunk of code in my controller to send an email. It currently looks like this:
from = Email.new(email: 'some#email.com')
to = Email.new(email: 'some#email.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: 'key')
response = sg.client.mail._('send').post(request_body: mail.to_json)
Ideally, I'd like to be able to trigger it from a service like: SendMail.new.perform() or some nice one-liner in the controller.
How would I abstract this code away from the controller and how would I call that new service/abstraction?

Twilio SendGrid developer evangelist here.
You can absolutely extract that from your controller, this is normally described as a service object.
I like to keep service objects in the app folder. You can do so by creating the directory app/services. Then create a file for the class, app/services/email_service.rb for example. In that file add the code to send the email, maybe something like this:
class EmailService
def self.call(from:, to:, subject:, content:)
self.new.send_email(from: from, to: to, subject: subject, content:
end
def initialize()
#sendgrid = SendGrid::API.new(api_key: Rails.application.credentials.sendgrid)
end
def send_email(from:, to:, subject:, content:)
from = Email.new(email: from)
to = Email.new(email: to)
content = Content.new(type: 'text/plain', value: content)
mail = Mail.new(from, subject, to, content)
response = #sendgrid.client.mail._('send').post(request_body: mail.to_json)
end
end
You can then call this service from your controller with the one liner:
EmailService.call(from: "me#mydomain.com", to: "you#yourdomain.com", subject: "My new email service", content: "It's pretty wonderful")
As a bonus, it's also easier to unit test the EmailService separate to the controller and to mock it out in controller tests.

If you are using rails, you can define it in your environment file and use one line code to send email from your controller.
production.rb
config.action_mailer.delivery_method = :sendmail
# Defaults to:
# config.action_mailer.sendmail_settings = {
# location: '/usr/sbin/sendmail',
# arguments: '-i'
# }
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_options = {from: 'no-reply#example.com'}
and in your controller
mail( :to => #user.email,
:subject => 'Thanks for signing up for our amazing app' )
best case for using sendmail is using it with an ActionMailer class. You can look it up at rails documentation.

Related

mail attachment SendGrid using ruby

I am trying to send an email with an attachment in Ruby and I have the following line:
from = Email.new(email: 'mail#mail.com')
to = Email.new(email: 'mail#mail.com')
subject = 'file for this week'
content = Content.new(type: 'text/plain', value: 'Please find file for this week.')
mail = Mail.new(from, subject, to, content)
mail.attachments['test.txt'] = File.read("#{Rails.root}/public/test.txt")
sg = SendGrid::API.new(api_key:'myapikey')
sg.client.mail._('send').post(request_body: mail.to_json)
The issue is code by the following line (when I remove it, I receive an email):
mail.attachments['test.txt'] = File.read("#{Rails.root}/public/test.txt")
But when I try to run it, I get the following error:
undefined method '[]=' for nil:NilClass
Has anyone faced this error before?
Per the docs, normally you would create a new Mail object using a Hash with the values being Strings. It's hard to tell, because I don't know what your Email or Content classes are doing, but I suspect something is going wrong when you create mail. Let's get those unknown classes out of the picture for starters.
Try changing your code to:
from = 'mail#mail.com'
to = 'mail#mail.com'
subject = 'file for this week'
content = 'Please find file for this week.'
mail = Mail.new(from: from, to: to, subject: subject, body: content)
mail.attachments['test.txt'] = File.read("#{Rails.root}/public/test.txt")
sg = SendGrid::API.new(api_key:'myapikey')
sg.client.mail._('send').post(request_body: mail.to_json)

How do I pass unique_args to the SendGrid::TemplateMailer API from Ruby on Rails

I've been implementing the sendgrid-ruby gem to send email via SendGrid. I'm using templates exclusively for my messages to send. I've got everything working on the outbound side using the TemplateMailer implementation.
This is the code:
unique_args = {unique_args: {MyAuditNumber: "9999999"}}
# Create a sendgid recipient list
recipients = []
recipient = SendGrid::Recipient.new(to_email)
merge_vars.each do |mv|
Rails.logger.debug(mv)
recipient.add_substitution('*|' + mv["name"] + '|*', mv["content"])
end
recipients << recipient
# Create a sendgrid template
template = SendGrid::Template.new(template_id)
# Create a client
client = SendGrid::Client.new(api_key: Rails.configuration.sendgridkey)
mail_defaults = {
from: from_email,
from_name: from_name,
to: to_email,
to_name: to_name,
bcc: bcc,
html: ' ',
text: ' ',
subject: subject
}
mailer = SendGrid::TemplateMailer.new(client, template, recipients)
# send it
lres = mailer.mail(mail_defaults)
The last thing I want to do is to add a unique identifier to each message that I send.
I've read both the SendGrid documentation as well as several questions and other articles (
how to get response of email sent using sendgrid in rails app to save in database
http://thepugautomatic.com/2012/08/sendgrid-metadata-and-rails/
https://sendgrid.com/docs/Integrate/Code_Examples/SMTP_API_Header_Examples/ruby.html
)
I can tell that I need to add unique_args to the smtp API. But what I can't figure out is how to pass that into the SendGrid routines.
I've tried things like:
recipient.add_to_smtpapi( unique_args )
and
recipient.add_to_smtpapi( unique_args.to_json )
and
mail_defaults = {
smtpapi: unique_args,
from: from_email,
...
and
mail_defaults = {
smtpapi: unique_args.to_json,
from: from_email,
...
These attempts generally result in an error message like:
undefined method `add_filter' for "{\"unique_args\":{\"MyAuditNumber\":\"9999999\"}}":String
Does anyone know how to pass unique_args when using the TemplateMailer?
Based on gem documentation, what you should do is the following:
header = Smtpapi::Header.new
header.add_unique_arg("MyAuditNumber", "9999999")
mail_defaults = {
smtpapi: header
...

Send image inline in email using Rails 2

I am working on rails 2 application with sending email functionality. Now, I need to send inline image with the email.
I am using Mailer to send email. I tried lots of time using different ways but not succeed to send image inline in email. Below code i am using to send email.
# Controller
Mailer.delivery_my_opinion_reply(user, my_opinion, answer)
# Model / Mailer.rb
def my_opinion_reply(user, my_opinion, answer)
#subject = "My opinion"
#from = "#{Settings.site_name}"
#recipients = user.email
#content_type = "multipart/alternative"
#attachments.inline['test.jpg'] = File.read(RAILS_ROOT + "/public/system/att_images/728/original/ball1.jpg")
#body = {:question => my_question, :user => user}
end
I got error "undefined method inline for nil class"
try this way
#attachments.inline['image.png'] = File.read("app/assets/images/image.png")
mail(to: email, subject: "subject", content_type: "text/html")

how to get subject, from and body from mailman rails

i have code like this
Mailman::Application.run do
to 'email#local.com' do
## how to get subject, from and body in here
end
end
how to get subject, from and body from email in rails?
Use mail gem https://github.com/mikel/mail/
Mailman::Application.run do
default do
mail = Mail.new(message)
from = message.from.first
content = mail.parts[1].body.decoded
subject = message.subject
//your other code
end
end

How to use delayed job in rails observer with faraday

With the app I'm building, we're using trumpia to schedule and send sms, and email messages to our users. When they sign up, I'm using an observer to trigger the call to trumpia, and I'm using faraday to actually connect with the trumpia API. My problem is that these calls are taking a lot of time, and I need to put them into the background. I also have a smaller set of commands that I need to run immediately, so I can't just delay the whole after_create.
I'm thinking of using delayed_job to accomplish this, but I have no idea how to do it with something as convoluted as my code is. How can I do this? I think I need to put the Faraday calls into a method, but I don't know how. -- Thanks
Here's my observer. I've left out the code that isn't necessary.
class UserObserver < ActiveRecord::Observer
def after_create(user)
#This first part should not be delayed
#user = user
kevin = User.find(1)
user.increment!(:renewcash, by = 5)
body = "Hi " + #user.name.split(' ', 2).first + ", ..."
kevin.send_message(#user, body, "First message", sanitize_text=true, attachment=nil)
# This whole second part needs to be delayed.
conn = Faraday.new(:url => 'http://api.trumpia.com') do |faraday|
faraday.request :multipart
faraday.response :logger
faraday.adapter Faraday.default_adapter
end
trumpia_body = {:list_name => ... .... }.to_json
response = conn.put do |req|
req.url '/rest/v1/XXXXXXXXX/subscription'
req.headers['X-Apikey'] = 'XXXXXXXXXXXXX'
req.headers['Content-Type'] = 'application/json'
req.body = trumpia_body
end
response2 = conn.get do |req2|
req2.url '/rest/v1/XXXXXXXX/subscription?row_size=1'
req2.headers['X-Apikey'] = 'XXXXXXXXXXX'
req2.headers['Content-Type'] = 'application/json'
end
end
I'm using rails 3.2.8. But I haven't install delayed job yet, and I'm open to a different queing gem.

Resources