Ruby mail gem - search inbox from specific email addresses - ruby-on-rails

Does anybody know how to get mail from an array of email addresses using the 'mail' gem in Ruby? I've seen the thread for getting unread messages like so:
new_messages = Mail.find(keys: ['NOT','SEEN'])
But I cannot find how to get messages from a certain address. I've tried:
new_messages = Mail.find(keys: ['FROM','example#hello.com'])
but it doesn't work.
I know section 6.4.4 of the IMAP protocol indicates the different search flags you can use to search for messages, but I can't seem to make it work.

Unfortunately, neither
Mail.find( keys: ['FROM', from_address] )
nor
Mail.find( keys: "FROM #{from_address}" )
worked. What worked, however, is quoting the email address:
Mail.find( keys: "FROM \"#{from_address}\”" )
Luckily, it was just the missing quotes, as the array variant works as well when quoting the email address:
Mail.find( keys: ['FROM', "\"#{from_address}\”"] )

Try this for single email address
Mail.all.select { |mail| mail.from.addresses.include?('example#hello.com') }
And for multiple try this
addresses = ['example#hello.com', 'test#hello.com']
Mail.all.select { |mail| (addresses - mail.from.addresses).empty? }
Also if you want to find just first mail try this
Mail.all.find { |mail| mail.from.addresses.include?('example#hello.com') }

Related

AWS-SDK-SES: How Can I Check the Existence of an Email Address in Rails?

I currently have Rails applications that use SES to send emails. Unfortunately no matter how much code I put in my application I still get emails with invalid email addresses.
I want to use AWS to verify if I have a valid email address, meaning that the syntax is correct and does other verification like checking if the mailbox exists.
I installed the aws-sdk-rails gem in my application. I added my access_key_id and secret_access_key to config/credentials.yml.enc.
I added the following code from this awsdocs/aws-doc-sdk-examples GitHub repository to my contact form and made minor changes.
require 'aws-sdk-ses'
# Replace recipient#example.com with a "To" address.
recipient = params[:email]
error = " "
# Create a new SES resource in the us-west-2 region.
# Replace us-west-2 with the AWS Region you're using for Amazon SES.
ses = Aws::SES::Client.new(region: 'us-west-2')
# Try to verify email address.
begin
ses.verify_email_identity({
email_address: recipient
})
puts 'Email sent to ' + recipient
# If something goes wrong, display an error message.
rescue Aws::SES::Errors::ServiceError => error
puts "Email not sent. Error message: #{error}"
end
I entered an email address that AWS SES said that the mailbox didn't exist this morning. However when I ran this code it didn't produce an error as I thought it might. When I checked the Rails debug log error was blank. The region in my code is the one that I use to successfully send transactional emails from all my websites.
I couldn't find any documentation about that code that says how much verification it does for the email address.
Can I use this gem to find if email addresses exist or have other problems like SES checks when an email has a To: email address?

Grails mail plugin send from differnet emails

I have a list of persons with individual emails (on different kind of mail services, for example gmail and hotmail). I want to send mail from their respective email addresses, like this:
mailService.sendMail {
from "hereMail#some.com"
}
In order to send mail I must set the configuration in Config.groovy. Should I maintain all emails configuration in Config.groovy file? or some other solution exist for this problem?
The configuration only allows the sending from one SMTP server. The account that sends the email is not necessarily the "from" address even though it is being emailed from that account. You should be able to use one account as the SMTP server and change the "from" as needed.
The configuration item sets the "default" from address for outgoing messages. The plugin provides a DSL that is used to specify the components of the message, including a specific From address if you want. If you don't provide a from specification in the message DSL, then it uses the configuration specified value.
Here is a snippet of code that I use in my messaging system to set a user account supplied from address on outgoing messages:
mailMessage = mailService.sendMail {
multipart true
if (toAddresses) { to toAddresses }
if (ccAddresses) { cc ccAddresses }
if (bccAddresses) { bcc bccAddresses }
from messageSpecification.from
subject messageSpecification.subject
if (messageSpecification.plainText) { text messageSpecification.plainText }
if (messageSpecification.htmlText) { html messageSpecification.htmlText }
messageSpecification.attachments.each {
attach(it.filename, it.mediaType, it.data)
}
}
Simply replace the messageSpecification.from reference to your specific from address and you are good to go.

Read Gmail XOAUTH mails without marking it read

I'm trying to read email from GMail using gmail-xoauth Gem. I want to read the email and leave its unread status.
First, I tried reading just the header. Works.
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
imap.authenticate('XOAUTH2', email, access_token)
imap.select('INBOX')
imap.search(["SINCE", since]).each do |message_id|
msg = imap.fetch(message_id,'RFC822.HEADER')[0].attr['RFC822.HEADER']
mail = Mail.read_from_string msg
puts mail.subject
end
Now, I want to read the body/text of the Email without marking it read.
This maybe be very late but I will leave it here for anyone else that stumbles onto this. If, for what ever reason you want to read the email and leave the flags intake, use:
imap.examine('INBOX')
instead of:
imap.select('INBOX')
From the Net::IMAP doc
Sends a EXAMINE command to select a mailbox so that messages in the mailbox can be accessed. Behaves the same as select(), except that the selected mailbox is identified as read-only.
Based on the documentation you need to use the store method. The documentation mentions:
store(set, attr, flags)
Sends a STORE command to alter data associated with messages in the mailbox, in particular their flags. The set parameter is a number or an array of numbers or a Range object. Each number is a message sequence number. attr is the name of a data item to store: ‘FLAGS’ means to replace the message’s flag list with the provided one; ‘+FLAGS’ means to add the provided flags; and ‘-FLAGS’ means to remove them. flags is a list of flags.
The return value is an array of Net::IMAP::FetchData. For example:
p imap.store(6..8, "+FLAGS", [:Deleted])
#=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
#<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
#<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
So you have to remove the :Seen flag
imap.store(message_id, "-FLAGS", [:Seen])

find email and replace with a sentence in PHP

How do I prevent people from entering their email address in the description field by replacing their email to some wordings, for example if user entered the following text:
Please contact me via joe.joey#email.com.
I want the output to be:
Please contact me via <email address is blocked>.
I know of a basic str_replace but the output would simply be:
//output is Please contact me via joe.joey <email address is blocked> email.com
$string = 'Please contact me via joe.joey#email.com.';
$lookfor = '#';
$replacewith = '<email address is blocked>';
$newstring = str_replace($lookfor, $replacewith, $string);
thanks.
This is a perfect time to use preg_replace. I've slightly simplified the requirements for a valid email here (emails can be horridly complex), but something like:
$newstring = preg_replace("/[\w-]+#([\w-]+\.)+[\w-]+/", $replacewith, $string);

While processing an email reply how can I ignore any email client specifics & the history?

I have a rails application which processes incoming emails via IMAP. Currently a method is used that searches the parts of a TMail object for a given content_type:
def self.search_parts_for_content_type(parts, content_type = 'text/html')
parts.each do |part|
if part.content_type == content_type
return part.body
else
if part.multipart?
if body = self.search_parts_for_content_type(part.parts, content_type)
return body
end
end
end
end
return false
end
These emails are generally in response to a html email it sent out in the first place. (The original outbound email is never the same.) The body text the method above returns contains the full history of the email and I would like to just parse out the reply text.
I'm wondering whether it's reasonable to place some '---please reply above this line---' text at the top of the mail as I have seen in a 37 signals application.
Is there another way to ignore the client specific additions to the email, other than write a multitude of regular expressions (which I haven't yet attempted) for each and every mail client? They all seem to tack on their own bit at the top of any replies.
I have to do email reply parsing on a project I'm working on right now. I ended up using pattern matching to identify the response part, so users wouldn't have to worry about where to insert their reply.
The good news is that the implementation really isn't too difficult. The hard part is just testing all the different email clients and services you want to support and figuring out how to identify each one. Generally, you can use either the message ID or the X-Mailer or Return-Path header to determine where an incoming email came from.
Here's a method that takes a TMail object and extracts the response part of the message and returns that along with the email client/service it was sent from. It assumes you have the original message's From: name and address in the constants FROM_NAME and FROM_ADDRESS.
def find_reply(email)
message_id = email.message_id('')
x_mailer = email.header_string('x-mailer')
# For optimization, this list could be sorted from most popular to least popular email client/service
rules = [
[ 'Gmail', lambda { message_id =~ /.+gmail\.com>\z/}, /^.*#{FROM_NAME}\s+<#{FROM_ADDRESS}>\s*wrote:.*$/ ],
[ 'Yahoo! Mail', lambda { message_id =~ /.+yahoo\.com>\z/}, /^_+\nFrom: #{FROM_NAME} <#{FROM_ADDRESS}>$/ ],
[ 'Microsoft Live Mail/Hotmail', lambda { email.header_string('return-path') =~ /<.+#(hotmail|live).com>/}, /^Date:.+\nSubject:.+\nFrom: #{FROM_ADDRESS}$/ ],
[ 'Outlook Express', lambda { x_mailer =~ /Microsoft Outlook Express/ }, /^----- Original Message -----$/ ],
[ 'Outlook', lambda { x_mailer =~ /Microsoft Office Outlook/ }, /^\s*_+\s*\nFrom: #{FROM_NAME}.*$/ ],
# TODO: other email clients/services
# Generic fallback
[ nil, lambda { true }, /^.*#{FROM_ADDRESS}.*$/ ]
]
# Default to using the whole body as the reply (maybe the user deleted the original message when they replied?)
notes = email.body
source = nil
# Try to detect which email service/client sent this message
rules.find do |r|
if r[1].call
# Try to extract the reply. If we find it, save it and cancel the search.
reply_match = email.body.match(r[2])
if reply_match
notes = email.body[0, reply_match.begin(0)]
source = r[0]
next true
end
end
end
[notes.strip, source]
end
I think you will be stuck on this one. I have been doing some stuff with emails myself in TMail recently, and what you will generally find is that an email that has an HTML part is generally structured like:
part 1 - multipart/mixed
sub part 1 - text/plain
sub part 2 - text/html
end
The email clients I have played with Outlook and Gmail both generate replies in this format, and they just generally quote the original email inline in the reply. At first I though that the 'old' parts of the original email would be separate parts, but they are actually not - the old part is just merged into the reply part.
You could search the part for a line that begins 'From: ' (as most clients generally place a header at the top of the original email text detailing who sent it etc), but its probably not guaranteed.
I don't really see anything wrong with a --- please reply above this line --- generally, its not that invasive, and could make things a lot simpler.

Resources