mail attachment SendGrid using ruby - ruby-on-rails

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)

Related

Emails with SendGrid Web API in 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.

Send sender name with email SendGrid - Rails

I am using SendGrid to send emails from my application. I want to send sender name along with sender email e.g. from: 'Maxcreet <contact#maxcreet.com>'
It is working fine using Letter Opener and MailTrap but SendGrid only show sender email.
Here is my SendGrid functionto send emails.
def deliver!(mail)
email.from = SendGrid::Email.new(email: mail[:from].addrs.first.address)
email.subject = mail.subject
email.add_personalization(build_personalization(mail))
build_content(mail)
send!(email)
end
I have checked mail[:from] values using puts it gives following values:
puts mail[:from] => Maxcreet <support#maxcreet.com>
puts mail[:from].addrs => Maxcreet <support#maxcreet.com>
puts mail[:from].addrs.first => Maxcreet <support#maxcreet.com>
puts mail[:from].addrs.first.address => support#maxcreet.com
Above 3 seems OK for me but when I use any of them in
email.from = SendGrid::Email.new(email: mail[:from].addrs.first.address)
It does not sent my email and even I do not find my email in sendgrid dashboard.
Following this also tried email.fromname but this even did not work.
SendGrid's ruby API has this option with name name and not fromname.
So the following should solve your problem.
email.from = SendGrid::Email.new(
email: mail[:from].addrs.first.address,
name: mail[:from].addrs.first.name
)
I concluded this by trying it from this doc.
It looks like you're mixing gems or objects. SendGrid::Email.new just needs a from String, and might support a name String. You're extracting the address from your mail[:from] Hash with mail[:from].addrs.first.address, but you need to provide the name as a distinct Key.
In the SendGrid Ruby gem 'kitchen sink" example, they don't show a name on the From argument, but they do on the personalization.
Try: email.from = SendGrid::Email.new(email: 'support#maxcreet.com', name: 'Maxcreet'))
or dynamically: email.from = SendGrid::Email.new(email: mail[:from].addrs.first.address, name: mail[:from].addrs.first.name))
if your mail Object recognizes that Key.
Otherwise, you'll need to look at your mail gem's documentation for how to extract a Friendly/Display Name from that mail[:from].addrs Object.

Rails 5 add link_to in mailer text

I am using Mail-factory to sending email from my Rails 5 application. Here I need to include link which will take users to corresponding page.
The code which I have done in my controller is
url = "http://localhost:3000/sample_page"
mail = MailFactory.new()
mail.to = ApplicationController.admin_user_email
mail.from = "from_eail"
mail.subject = subject
mail.text = "Hi, view_context.link_to(Test, url)"
But while receiving email, the content is like,
Hi Test
But I need to show my link as like.
Hi [Test][1]
Please correct me if I were wrong.
Try to the following
mail.text = "Hi, [#{view_context.link_to('Test', url)}]".html_safe
If you're passing in the URL as a variable, you should be able to just print it out like this:
mail.text = "Hi [Test][#{url}]"

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")

Resources