How to handle forwarded e-mails in Rails ActionMailbox? - ruby-on-rails

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.

Related

Rails - Logging events with tags or types and getting an email alert - best practices?

Wondering if someone could offer some best practice on logging techniques they use and maybe tagging certain events using airbrake or newrelic or loggly, or something of that nature?
For example, lets say I have events that should never hit my controller in theory, because they are protected on the front end - like a regular user being able to manage an admin. I prevent these controls from being outputted on the front end using ruby if statements. So if my controller gets hit with a request like this, then I know that either that code isn't working right, or someone is doing some hacking with the request being sent.
Either way I want to know. I just found myself writing:
#TODO: Log this. Either the front end is broken or the user is sending hacked requests
Wondering if anyone can offer some insight as to how they handle it, maybe with a third party logging tool, maybe with some sort of tag that I could set up email alerts with said tool?
Morgan from Airbrake here. We don't have tagging for Airbrake Exceptions.
One way to solve this with our service is to send a custom error to Airbrake from your controller.
The error will trigger an Airbrake notification email and you will be notified.
For Example:
# find me in app/controllers/some_controller.rb
# custom error
class ControllerAccessError < StandardError
end
def action
...
msg = 'front end is broken or the user is sending hacked request'
e = ControllerAccessError.new(msg)
Airbrake.notify_or_ignore(e)
end
Here is some more info on manually sending errors to airbrake with ruby:
https://github.com/airbrake/airbrake/wiki/Using-Airbrake-with-plain-Ruby
Jason from Loggly here. You can also setup a new Logger and then log anything you like. This uses pure Ruby code without any proprietary libraries. For example:
logger.warn("Regular user should not have access")
Even better, you can use JSON fields to make for easy reporting and filtering. I'm not a Ruby programmer, but I think it'd look something like this?
logger.warn({:username => username, :type => "Access Violation", :message => "Regular user should not have access"}.to_json);
In Loggly, you can setup alerts to be sent over email whenever you get a message matching this search
json.type:"Access Violation"

How do I get ActionMailer to log sent messages but NOT include the attachments?

I like that Rails automatically logs all messages that are sent out from the app. What I don't like is how it fills up my log file with huge blocks of useless Base64-encoded text. This makes looking through the log file a pain because I have to skip past these megabytes-long blocks of unreadable noise. It also causes the log file to grow too quickly and fill up the disk.
How can I get it to still log all messages that are sent but NOT include any of the attachments? Is there a way to tell it to strip out the attachments before logging or something?
Usually all I'm interested in seeing are the headers (subject, who it was sent to) and (at least some of the time) the message body text.
It wouldn't hurt to also have a list of the attachments (file name and type) too — but it certainly does me no good to see the full Base64 dump of all the attachments! (If I want to check and see if the attachments are coming through okay, I already know how to add a mail interceptor that bcc's all outgoing mail to my inbox.)
I ended up having it log the following details about each mail that gets sent out:
The headers
The structure of the email (which parts are within which other parts), including a list of attachments, before stripping out all
attachments
Decoded, human-readable, searchable message bodies (the Rails default is to log the encoded, which is hard for a human to read
and breaks words in random places, making it hard to search)
To accomplish this, I overrode ActionMailer::Base.set_payload_for_mail in my app and replaced this line:
payload[:mail] = mail.encoded
with a version that:
Creates a copy of the Mail object
Calls mail.without_attachments!, and
Only logs:
mail.header.encoded
the output from mail.inspect_structure (from my fork)
the result of calling part.decoded for each (non-attachment) part.
Check out this gist for the whole thing.
Logging of the message body is handled here:
https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/log_subscriber.rb#L14
module ActionMailer
class LogSubscriber < ActiveSupport::LogSubscriber
def deliver(event)
info do
recipients = Array(event.payload[:to]).join(', ')
"\nSent mail to #{recipients} (#{event.duration.round(1)}ms)"
end
debug { event.payload[:mail] }
end
# ... more methods ...
end
end
If you want to exclude the mail body entirely you can change the log level to exclude 'debug'. Otherwise you're only option is to override this method and do your own thing.
Unfortunately event.payload[:mail] is a String. Removing attachments could be messy. Showing just the headers wouldn't be that hard with a regex. Otherwise you'd need to recreate the Mail object from that string and extract what you want.
Another option would be to change the logger used by ActionMailer so that it logs to it's own file. That would at least keep your standard Rails log clean.
https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/railtie.rb#L12

How to get email reply on rails app from email server

I need to implement messaging feature. When I send message to any user from my rails app then it also goes to users email. But what I need to implement if user who got the email make reply from gmail,yahoo..etc then the reply should also come into rails app. could anyone guide me some way.. so I can search it on google.
For Example:
If I send email to user from this email "mc-6bckm434ls#reply.xyz.com" and user replied on gspq5diedss#reply.xyz.com which I set Reply-To in header. Then I need user's reply in my rails application so that I can add this user's reply into my messaging thread.
By this feature which I want to implement User do not need to login in my application to do message, user can do message on current conversation via email reply also.
Since you tagged the question SendGrid, I'm assuming you're using it. You can use SendGrid's Inbound Parse Webhook to handle parsing incoming messages.
We also have a recent tutorial that goes through using the webhook in a rails app: http://sendgrid.com/blog/two-hacking-santas-present-rails-the-inbound-parse-webhook/
It's possible !
You can use mailman for example.
All you have to do is set a Reply-To header in your e-mail to make it unique, so when you fetch messages you know to what it corresponds.
For example, let's say you own the e-mail address foo#bar.com
You could send e-mails with a reply-to header "foo+content_id#bar.com", so you know what the user is replying to.
Then, mailman can fetch the messages from the mailbox and parse the content id in them.
Some services do that as well, handling all the emailing part and sending you notifications for incoming e-mails, for example, postmark
Ruby on Rails introduced Action Mailbox in version 6.0
With ActionMailbox you can easily configure rules where to route incoming emails (examples from the documentation):
# app/mailboxes/application_mailbox.rb
class ApplicationMailbox < ActionMailbox::Base
routing /^save#/i => :forwards
routing /#replies\./i => :replies
end
And how to handle specific messages in a mailbox:
# app/mailboxes/forwards_mailbox.rb
class ForwardsMailbox < ApplicationMailbox
# Callbacks specify prerequisites to processing
before_processing :require_forward
def process
if forwarder.buckets.one?
record_forward
else
stage_forward_and_request_more_details
end
end
private
def require_forward
unless message.forward?
# Use Action Mailers to bounce incoming emails back to sender – this halts processing
bounce_with Forwards::BounceMailer.missing_forward(
inbound_email, forwarder: forwarder
)
end
end
def forwarder
#forwarder ||= Person.where(email_address: mail.from)
end
def record_forward
forwarder.buckets.first.record \
Forward.new forwarder: forwarder, subject: message.subject, content: mail.content
end
def stage_forward_and_request_more_details
Forwards::RoutingMailer.choose_project(mail).deliver_now
end
end
Find the documentation about how to configure Action Mailbox and some examples in the Rails Guides.
See https://github.com/titanous/mailman/blob/master/USER_GUIDE.md
There is a railscast about using the gem but its pay-only :-/ http://railscasts.com/episodes/313-receiving-email-with-mailman,
however, there is the github repo from the railscast which can showcase you an example app that uses mailman (with before & after so you can track the changes) - https://github.com/railscasts/313-receiving-email-with-mailman

Forward a mail using Tmail & ActionMailer::ARMailer

I'm writing a rake task to go through one of our mailboxes of incoming mail, using Tmail. For certain mails, i just want to forward them on to another address. I'm not sure what the best way to do that is though.
Our regular mails for the website are sent out using ARMailer: i call Mailer.deliver_ and the mail is generated from a template and put into our Email table, which in accessed by ARMailer which actually sends the mails out. So, the class definition of my Mailer class looks like this:
class Mailer < ActionMailer::ARMailer
#list of methods here, one per email type
end
So, what i want to do, is, in my script when i have a Tmail object representing the incoming mail, is to generate a new mail to stick into our mail queue which is basically the Tmail mail, forwarded onto a new address. I'm not sure what the best way to do that is. I could build up a new multipart mail copying the body, subject and from field from the recieved Tmail object, but that seems like it might be a bit clumsy, and that there should be a nicer way.
Can i do something like
newmail = Mailer.create_forward(my_tmail_object)
newmail.to = "forwardingaddress#domain.com"
newmail.deliver
??
Mailer/ARMailer doesn't have the create_forward method but it's something like that that i'm after. Any advice welcome! thanks

Checking for new emails from within Rails

Within Rails, how can I listen for new mail coming into the boxes of certain accounts. I want to implement a simple "post-by-email" service, which gets the new content of the email and makes a blog post or sth.
You could try this gem.
I wrote a post explaining some of the options. A later post also covered my way of testing these options. The mail gem is great for parsing. You just have to decide the best option for you to optain the messages.
http://steve.dynedge.co.uk/2010/09/07/incoming-email-in-rails-3-choosing-the-right-approach/
I use this code to parse my emails.
class Receiver < ActionMailer::Base
def self.parse(email)
reply_separator = /(.*?)\s?== ADD YOUR REPLY ABOVE THIS LINE ==/m
comment_text = reply_separator.match(email.body.to_s)
# ...
end
end
The email object here is just a Mail::Message object which I get from using the gmail gem to read an inbox. If you're not using GMail then you should be able to use plain ol' vanilla Mail gem to connect to the mail server and then get the Mail::Message objects that way.

Resources