How do I parse text from email body using a Rails3 app? - ruby-on-rails

I need to get the name and email address from a forwarded email where there is a line like this in the body:
From: john smith <sales#domain.com>
What is the best way to do this? Is there a good library/gem I should use?
Also this line will vary from which email client it's sent from and also what language, so I need a more robust way than just matching just this string.
Also some clients do not include the name but just the email address on this line so I need to be able to handle that.

require 'mail' # only needed for non-Rails
m = Mail.new( "any RFC-conforming email including headers" )
puts m[:from].display_names.first
puts m[:from].addresses.first
The Mail object is automatically included in Rails projects that use ActionMailer - but you'll need to add it to your Gemfile if you're not using ActionMailer
Update
I didn't read the OP's question properly - they want to get an email address from the body of a forwarded mail. I'd just use some regex:
name, email = m.body.match( /^\s*From:\s*(.*)\s+<(.*)>$/)[1,2]
NB: this assumes a fair amount about the structure of the email - an HTML-only email can easily thwart this regex.

Related

How to handle forwarded e-mails in Rails ActionMailbox?

We are using Rails 7 to build an application which, amongst other features, should perform some actions when e-mails are sent to one of its e-mail addresses (which have, for instance, the format ticket-{uuid}#ourdomain.com).
Rails' ActionMailbox's routing works fine for direct e-mails. However, when e-mails are forwarded, they are not recognized by ActionMailbox at all.
How can we ensure that forwarded e-mails are also handled and routed correctly with ActionMailbox?
EDIT: A simplified version of the code we are using:
class ApplicationMailbox < ActionMailbox::Base
routing /^ticket-(.+)#ourdomain.com$/i => :service_tickets
end
class ServiceTicketsMailbox < ApplicationMailbox
def process
puts "processing email: #{mail.inspect}"
# ... and then we extract its fields
# and store some of them in the database.
end
end
Ok I think I found the issue:
When you send a normal e-mail the To header looks like this To: ticket-123##ourdomain.com and this matches with /^ticket-(.+)#ourdomain.com$/i
However when you forward the e-mail the header looks like this To: John Doe <ticket-123#ourdomain.com> and this will not match with your regex.
Change the regex to /ticket-(.+)#ourdomain.com/i and it should work.
You can try it out on https://regexr.com/
The API never includes functionality to see any other mail-address than the latest one in the delivery stack.
The only option the API offers by itself is to use InboundEmail::source to get the raw message for further parsing.
After this process I could imagine to use RoutingJob to forward the mail to the correct receiver.
I'm not sure if Callbacks could help.
Also concerning MessageId I don't know if it's possible to extract the correct Ids.
As far as I see the whole challenge requires at least some work and I see there no simple solution.

Multiple recipients using Mandrill and Rails

I'm using ruby to send transactional emails via Mandrill.
As part of my product, I want to be able to send the same email to two recipients and have them see each other's email address.
(Like an introduction mail between two people).
So I filled he "to" field with both emails, and on my dashboard is seems that both are sent.
But unfortunately only one of the recipients receive the mail and the details of the second recipient is hidden.
In conclusion, I have two problems:
Only one recipient gets the mail
Hidden details of the second recipient.
I approached Mandrill support and this is what they replied:
If you'd like to enable this option globally for all of the messages you send, then you'll want to ensure that you have the
"Expose The List Of Recipients When Sending To Multiple Addresses"
option enabled in your Sending Defaults.
If, instead of making that change globally, you'd like to enable it
for individual messages, you'll want to use the
X-MC-PreserveRecipients (SMTP header), or the preserve_recipients (API
parameter), and set it to 'true'.
If you set this option to true, we'll expose the list of recipients to
each other as you would see happen when sending mail from a typical
email client program.
It worked!
If you want both recipients to be able to see each other, you can pass an array of e-mails in the to option.
If you do not want either of them to see each other, you can, in a loop over the users, send said e-mail.
If using ActionMailer it can be done like so:
mail(
to: ['person1#gmail.com', 'person2#gmail.com']
)
Or in a loop:
[user1, user2].each do |user|
UserMailer.some_email(user).deliver_now
end
mail(
to: user.email
)
Post your code, I have an idea of what your problem may be. Remember that a method in an ActionMailer class should only return mail() and must not be looped over inside of that method.
tldr: do everything unrelated to e-mail outside mailer, pass through necessary data as params to the method, end method with mail() call.

Catch emails to all a_user_name#mydomain.com, and execute code

In my webapp I have instances where I want to let users send an email to their local representative. But I don't want to expose that user's email so I'd like to have the email sent from a_user_name#mydomain.com, where a_user_name is different depending on who sends it.
Where I'm lost is how to handle the situation where somebody replies to that email, and I need to deliver it to the original author. I'd like to be able to catch that email, look up the user in our database, and send them an email notifying them of the reply. How do I complete this last part?
Using Rails + Amazon SES
Thanks!
You can integrate with a transactional email provider like Mandrill (or others). There's various mandrill rails gems to help.
See: https://mandrill.zendesk.com/hc/en-us/articles/205583197-Inbound-Email-Processing-Overview
The inbound email gets picked up in a controller like:
class InboxController < ApplicationController
include Mandrill::Rails::WebHookProcessor
def handle_inbound(event_payload)
#parse event_payload and take appropriate action
end
end
You can then parse that email to get the sender validate it against your user table and pass the message on or whatever.
You probably want to set a subdomain of your domain or a totally separate domain so you can route your normal email traffic to your mydomain.com mailservers and pick up the emails to be parsed by rails / processed by the webhook from mail.mydomain.com or whatever.
you can use Base64.encode64
2.0.0-p481 :029 > encrypted_email=Base64.encode64('mike#gmail.com')
=> "bWlrZUBnbWFpbC5jb20=\n"
2.0.0-p481 :030 > Base64.decode64(encrypted_email)
=> "mike#gmail.com"
OR MessageEncryptor
2.0.0-p481 :037 > crypt = ActiveSupport::MessageEncryptor.new(Rails.configuration.secret_token)
=> #<ActiveSupport::MessageEncryptor:0xcd4d6fc #secret="c07692942cde247c96ea3da23a4d6406ebdad7c37f63c13e100731ce03ce24088dbe419da154fb7e504e777c60c7f6f8850d27f8cb8b7968602244ce5c21bfb3", #cipher="aes-256-cbc", #verifier=#<ActiveSupport::MessageVerifier:0xcd4d4e0 #secret="c07692942cde247c96ea3da23a4d6406ebdad7c37f63c13e100731ce03ce24088dbe419da154fb7e504e777c60c7f6f8850d27f8cb8b7968602244ce5c21bfb3", #digest="SHA1", #serializer=ActiveSupport::MessageEncryptor::NullSerializer>, #serializer=Marshal>
2.0.0-p481 :038 > encrypted_data = crypt.encrypt_and_sign('mike#gmail.com')
=> "UjF4VFRnRnF1RVJnZXhUUm1KakJZcDFMN1ZoZXVzSmFvLzUwdFkydXNjYz0tLTlsbFI3Vlo4RUNVK2pMZVEzS2tSOWc9PQ==--710d4fcdc202e1b1143e12661d8b40831525f158"
2.0.0-p481 :039 > decrypted_back = crypt.decrypt_and_verify(encrypted_data)
=> "mike#gmail.com"
So.you may use a dedicated table to store both encrypted and original emails and then use it in the FROM section of mail as well as to refer it for future use .So you must use a Generic email id that users can use to reply and then you may send this encrypted hidden field which will identify which email id was intended to send and again send to that email.
i know it would be a two way process like:-
Encrypt email in From part and use Generic email where users can reply back
Use hidden field containing encrypted mail
So,if the user replies back to the Generic mail,check the encrypted mail from hidden field and then again resend it to the decrypted email.
HOPE THIS HELPS.

How to to mass email (500,000) using rails [duplicate]

I will be sending bulk emails from a Rails app and plan on using SendGrid. I am assuming that it is best to send a separate email to each recipient (as opposed to using BCC for all the recipients). If that is true, should I be using something like DelayedJob to queue the messages going over to SendGrid, or would it be safe to throw 500 messages at it all at once? Thanks!
500 messages really isn't that much to SendGrid. It's not even a blip on their radar. I worked for a company that sent out 2.7 million emails in a single month, and even then it's only just a blip.
With the SendGrid API's capabilities, you wouldn't be sending out 500 emails, you would send one email which has a specific SendGrid API header set. Why? Because have you ever tried to send 500 individual email messages and timed how long that takes? How about a single email? The single email's going to be quicker.
The SendGrid API has a Ruby example which is here:
https://sendgrid.com/docs/Integrate/Code_Examples/SMTP_API_Header_Examples/ruby.html.
That's quite long winded and messy, so let me simplify it for you. Basically, you set this in your email:
headers["X-SMTPAPI"] = { :to => array_of_recipients }.to_json
SendGrid will then parse this and then send that one email you sent it out to that array of recipients. I seem to recall that they ask you to limit this to about 1000 recipients per email, so it would be wise to split it up over multiple emails if you wanted that. That is when you would bring in something like the delayed_job or resque gems to deal with it.
Oh, and by the way you'll still need to specify a to address for this email just to make the Mail gem happy. We had info#ourcompany.com for that.
The SendGrid API will also support filters in their emails, so you can have placeholder strings such as {{ firstname }} and, assuming you send it through with the SMTPAPI header, it will do the "mail merge" on the email and customize them.
It would do you a great deal of good if you read the SendGrid API documentation. It's really useful and what they provide is super powerful.
I recommend using the sendgrid gem ( https://github.com/stephenb/sendgrid ) as it simplifies your calling code.
Here's an example rails 3 action mailer example:
class UserAnnouncementMailer < ActionMailer::Base
include SendGrid
default reply_to: "test#test.com", return_path: "test#test.com", from: "Test"
# bulk emailer
# params - opts a hash of
# emails: array of emails
#
def notice(opts={})
raise "email is nil" unless opts[:emails]
sendgrid_category :use_subject_lines
sendgrid_recipients opts[:emails]
name = "The Man"
to = "test#test.com"
from_name = "#{name} <theman#test.com>"
subject = "Important"
mail({from: from_name, to: to, subject: subject})
end
end
And the corresponding calling code. It's recommended to have the emails array to be < 1000 emails.
emails = ["alice#test.com", "bob#test.com"]
UserAnnouncementMailer.notice({:emails => emails}).deliver
See the sendgrid gem github readme for more details.
Delayed Job and SendGrid sound like the best option from what you say, but have you considered using one of the campaign mailers like Mailchimp instead? If you're sending out a lot of mails that are basically the same, they'll let you setup and campaign template and then fire a CSV of all the variables at it. They then effectively mail merge and fire them all out.
If however, you're only talking a few hundred you're on the right lines. SendGrid can easily handle the load, and you want to use Delayed Job so that you're not impacted by the performance of the SendGrid API should it not be favorable. Alternatively, look at Resque instead for sending mail as it may be more efficient.
I would imagine SendGrid can handle that kind of load. Most relay systems can. Also I would imagine if you sent the 500 in a CC API call, that their system would parse it and send them individually. I use Elastic Email (http://elasticemail.com) - and I know that this is how they handle it and it works great.
This is how I've done it in Rails 4
class NewsMailer < ApplicationMailer
include SendGrid
sendgrid_category :use_subject_lines
default from: 'My App! <support#myapp.com>'
def mass_mailer(news)
# Pass it in template
#news = news
# Custom method to get me an array of emails ['user1#email.com', 'user2#email.com',...]
array_of_emails = #news.recipients.pluck(:email)
# You can still use
# headers["X-SMTPAPI"] = { :to => array_of_emails }.to_json
sendgrid_recipients array_of_emails
mail to: 'this.will.be.ignored#ignore.me', subject: 'Weekly news'
end
end

How to send emails with return-receipts in Ruby on Rails?

I have to send automatic emails with Return Receipt (aka "acknowledgement of receipt"), to have the confirmation that the receiver have actually received and read the email. The confirmation is a simple email sent to a specified address (the "Disposition-Notification-To" address, given in the email header).
Do you know if there is an easy way to do that with Rails (ActionMailer)? or with Ruby perhaps (TMail, Net/SMTP)?
Thanks in advance for your help.
You set your headers in your mailer def block like so:
headers['Return-Receipt-To'] = 'email#example.com'
headers['Disposition-Notification-To'] = 'email#example.com'
headers['X-Confirm-Reading-To'] = 'email#example.com'
Note that these trigger a dialogue in some, but not all email clients. Also, it is not a guarantee that the receiver actually has read and understood the email.

Resources