I am currently receiving emails from Amazon SES, which I store on Amazon S3.
Then I have a program (written in Java) which retrieve emails from S3, parse them and do a specific action based on the recipient's name.
The issue
When an email is sent to 2 recipients (let's say A#mydomain.com and B#mydomain.com), Amazon SES receive 2 emails and store both of them in S3.
Both emails are identical (except for some custom headers set by my email client).
My Java program retrieve 2 emails from S3 but I can't determine for whom each email is intended, as both email addresses are present in the "TO" header of both emails.
What I found
Amazon SES store the MIME Message in S3
Based on the Internet Message Format RFC, MIME Message contains the full list of recipients, but not the actual recipient.
I guess this information is not part of the Mime Message, but part of the protocol.
It means that:
Amazon SES must know the recipient
Once the mail is stored in S3, this information is lost.
Based on the fact that this analyze is correct (which might not be), I wanted to use Amazon Lambda expressions to retrieve the protocols information and store them as metadata of the email in S3.
However, I cannot find a way to retrieve the protocols informations.
Any idea?
Does someone has any idea how to achieve this?
It would be nice if I could get the recipient's email address of each email from a Lambda expression, but I didn't found a lot of references about this.
Maybe my interpretation of how this work (the email protocol / process) is completely wrong and someone could give me some explanation! :D
Some code to go with it
I found some code displaying the information we have if we do a lambda function at the SES level, but I didn't find the information I needed there.
https://gist.github.com/gonfva/b249f76893165bf5a8d1
The S3Object also contains some Metadata but they don't seem to be useful.
Bellow is the Java code I use to retrieve emails from Amazon.
package fr.novapost.delivery.emailer.listener.amazon;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectId;
import org.apache.commons.mail.util.MimeMessageParser;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import java.util.List;
import java.util.Properties;
public class Main {
public static void main(String[] args) {
// Fill these variables with the proper values.
String objectName = "";
String bucketName = "";
String accessKey = "";
String secretAccessKey = "";
BasicAWSCredentials awsCred = new BasicAWSCredentials(accessKey, secretAccessKey);
AWSCredentialsProvider credentialProvider = new AWSStaticCredentialsProvider(awsCred);
// Create S3 client
AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard().withCredentials(credentialProvider).withRegion(Regions.EU_WEST_1).build();
// Retrieve object from S3
GetObjectRequest request = new GetObjectRequest(new S3ObjectId(bucketName, objectName));
S3Object s3Object = amazonS3.getObject(request);
// Get content of the object (which is the MimeMessage) and create a MimeMessage from it.
Session s = Session.getInstance(new Properties());
try {
MimeMessage mail = new MimeMessage(s, s3Object.getObjectContent());
// Parse the mime message thanks to the org.apache.commons.mail.util.MimeMessageParser class.
MimeMessageParser mimeParser = new MimeMessageParser(mail);
mimeParser.parse();
// Get the recipient's list.
// It contains ALL the recipients.
// I want to know for which specific recipient of this list this email was intended.
List<Address> addresses = mimeParser.getTo();
for (Address address : addresses) {
System.out.println("recipient: " + address.toString());
}
} catch (MessagingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
The recipients as they may be suggested by To: and Cc: mail headers are irrelevant, as those are not actually used for delivery (and in the case of BCC, the recipient should definitely not appear there).
You should find that SES adds the actual envelope recipient (which is what you are looking for) in the first Received: header from the top.
Return-Path: <...>
Received: from x-x-x (x-x-x [x.x.x.x])
by inbound-smtp.us-east-1.amazonaws.com with SMTP id xxxxxxxxxxxxxxxxxxxx
for the-actual-recipient-is-this-address#example.com;
Sat, 15 Jul 2017 05:07:18 +0000 (UTC)
X-SES-Spam-Verdict: PASS
X-SES-Virus-Verdict: PASS
Received: headers are prepended as mail is processed, so you they become less trustworthy as you work down -- but the top one comes from SES itself.
Related
I am setting up an app to send emails to clients. I am using Java and SendGrid to create this app, but I am having issues with the SendGrid authorization
I am getting the error:
java.io.IOException: Request returned status Code 401Body:{"errors":[{"message":"The provided authorization grant is invalid, expired, or revoked","field":null,"help":null}]}
Reading through some other posts with similar issues it seems most get resolved because people were using the API Key ID instead of the API Key. I have already checked to make sure that I am using the full key so I don't think that is the issue.
I have also tried to create a new API Key but that just gives the same issue. Finally, I have tried doing a similar call using Postman and that works just fine with the same API Keys.
This is the main class I am using to send emails.
import com.sendgrid.*;
import com.sendgrid.helpers.mail.Mail;
import com.sendgrid.helpers.mail.objects.Content;
import com.sendgrid.helpers.mail.objects.Email;
import java.io.IOException;
public class SendEmail {
public static void main(String[] args) throws IOException{
Email from = new Email("FROM_EMAIL");
String subject = "Sending with Twilio(?) is fun";
Email to = new Email("TO_EMAIL");
Content content = new Content("text/plain", "and easy to to anywhere, even with Java");
Mail mail = new Mail(from, subject, to, content);
SendGrid sg = new SendGrid(System.getenv("API_KEY"));
Request request = new Request();
try {
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
System.out.println(response.getStatusCode());
System.out.println(response.getBody());
System.out.println(response.getHeaders());
} catch (IOException ex) {
throw(ex);
}
}
I then call this class in my main class through this snippet:
try{
SendEmail.main(email);
} catch(IOException ex){
System.out.println(ex);
}
The "email" string is just a placeholder as otherwise I get an error saying that I need to have an array when I call the class. (Not sure why that is, could that be the root of the problem?)
Obviously sensitive information has been removed so that's why some of the fields look off.
By the way, I followed the tutorial in this github:
https://github.com/sendgrid/sendgrid-java
Let me know what you think.
Thanks in advance!
I think your environment variable was not setup properly. Try to execute the program without "System.getenv" as below.
SendGrid sg = new SendGrid("YOUR_API_KEY");
My apologies. I did not know "System.getenv" would get the environmental variables. I set up environmental variables and the issue is resolved.
I'm writing a program that has auto response in it. i.e. for example there is an user ad his email address would be user#domain.com, when ever someone writes an email to this address, there should be an auto response sent (Which I'm able to do it). but this should be sent from autoReply#domain.com(this is what I'm unable to know on how to do this). autoReply#domain.com is a shared mail box.
I'm using ews in my program and the below block of code is responsible to send the auto response.
private void replyToEmailWithURLs(ItemId itemId, List matchedKeyWords, String fromAddress) throws Exception {
EmailMessage message = EmailMessage.bind(service, itemId, new PropertySet(BasePropertySet.IdOnly));
ResponseMessage responseMessage = message.createReply(false);
message.getReplyTo().add(new EmailAddress("autoReply#domain.com"));
// Add autoReply in CC
responseMessage.getCcRecipients().add("autoReply#domain.com");
String responseUrls = getTheResponseUrlsFromJsonFile(matchedKeyWords, fromAddress);
responseMessage.setBodyPrefix(new MessageBody(BodyType.HTML, responseUrls));
responseMessage.sendAndSaveCopy();
message.setIsRead(true);
}
Here I tried to add a replyTo using message.getReplyTo().add(new EmailAddress("autoReply#domain.com"));, even this doesn't work.
I've seen a post here set reply-to address in outgoing email EWS , I was confused on the way it is working(basically given in c#), please let me know how can I get this done in Java.
Thanks
I'm not familiar with EWS, but apparently the standard JavaMail API supports setting From or the sender address.
I am facing one problem while extracting BCC address from incoming mail.
Here is the sample code that is used.
public EmailVO dumpEnvelope(Message m) throws Exception {
EmailVO emailVO = new EmailVO();
if ((addresses = m.getRecipients(Message.RecipientType.BCC)) != null) {
emailVO.setBcc(this.getAddresses(addresses, "BCC"));
}
}
I am getting null value in BCC.
While debugging I found BCC recipient's name in header field but I am not able to access that header.
Is this code issue or there is some specific setting while sending mail like not to include BCC fields?
The whole point of Bcc is that it's a blind carbon copy - the recipients don't get to see who was copied. You won't see Bcc fields in messages you receive. (Sometimes a Bcc'ed recipient will see the Bcc header in the messages they receive, but the other recipients will get a copy of the message without the Bcc. But I don't think many mailers do that anymore because it requires sending two different versions of the message.)
You can check your Message object which contains all the details about the mails.
As the BCC is the part of mail but also it will be hidden, but as per my knowledge you can retrieve the information from your mail headers.
Address[] addresses = m.getHeader("Your Header Name HERE");
This will give you all the details regarding your particular header tag in mails.
for e.g.
Address[] addresses = m.getHeader("Delivered-To");
This tag will give you all the information about the recipients of the mail, which will also include BCC.
you can also add your custom headers for mail.
addresses = m.getRecipients(Message.RecipientType.BCC);
returns an array of addresses. You can check the content in a for loop:
Address[] addresses = m.getRecipients(Message.RecipientType.BCC);
for(Address address : addresses){
System.out.println(address);
}
Does any one know how to send an email with the desired "from" name in Java ?
I have a code which sends the mail through gmail. Using the smtp settings of gmail, I am able to do that. But, using the same smtp settings, can I send an email from a non-existing mail ID ?
For example:
I have a code which sends an email from the existing username (say abc#gmail.com) and the receiver gets the email from abc#gmail.com . But , what I want is , can we send a mail from something like "a#def.com" ? So that, the user receives the mail from "a#def.com" ?
Is that possible ?
While the API may allow you to do that, your difficulty is going to be with the SMTP server's configuration. No sane SMTP server would allow you to control the "from" email address of email messages sent through that SMTP server - that's the first step of making your SMTP server an easy gateway for spammers. Proper SMTP servers (Google's included) will set the "from" email address to be identical to the one you logged in with.
You can set it explicitly. But again it depends on the SMTP server that accepts the FROM address. To my knowledge most of the SMTPs are configured to block the sender email ids that do not belong to its domain. If at all they are not configured so, the receiving mail clients may filter the message for not identifying the sender email id from the receiving server and set it as SPAM. This would also cause the SMTP domain being blocked by many other receiving domains.
Hence it is not suggested to be followed.
You need mail.jar and activation.jar. In my case i implemented using below method
import java.util.HashMap;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.internet.MimeMessage;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.Transport;
class ABC{
......
private void sendSimpleEmail(String to,String subject,String cc,String bcc,String message,HashMap mailMap)
{
String smtpHost=mailMap.get("mailhost").toString();
String smtpPort=mailMap.get("mailport").toString();
String authrequired=mailMap.get("auth").toString();
String from=mailMap.get("mailsendfrom").toString();
String SSLCheck=mailMap.get("sslconfig").toString();
/* For Authentication */
String password=mailMap.get("mailpwd").toString();
String fromUsername=mailMap.get("mailusername").toString();
/* For Authentication Ends*/
Properties props = new Properties();
props.put("mail.smtp.auth", authrequired);
props.put("mail.smtp.host", smtpHost);
props.put("mail.smtp.port", smtpPort);
Session session=Session.getDefaultInstance(props);
Message simpleMessage = new MimeMessage(session);
try {
InternetAddress fromAddress = new InternetAddress(from);
InternetAddress toAddress = new InternetAddress(to);
} catch (AddressException e) {
//Exception
}
try {
simpleMessage.setFrom(fromAddress);
simpleMessage.setRecipient(RecipientType.TO, toAddress);
simpleMessage.setSubject(subject);
simpleMessage.setText(message);
Transport.send(simpleMessage);
} catch (MessagingException e) {
// TODO Auto-generated catch block
}
}
.......
}
I am currently doing a project where I am required to send an email to the specific address taken from database. However, the column "email" in database does not actually contain emails, but names instead. So in database there are full names in russian language like
"Иванов Александр" which is "Ivanov Alexandr". So when I type this name in the outlook it automatically finds his email: AIvanov#domainname.com. But in my java code when I use name "Иванов Александр" i keep getting error.
Here is my java code
File[] listOfFiles = outDir.listFiles();
if (outDir.isDirectory()) {
if (outDir.list().length > 0) {
for (File file : listOfFiles) {
Session session_m = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session_m);
message.setFrom (new InternetAddress("mmm#domainname.com", "mmm#domainname.com"));
InternetAddress i = new InternetAddress("\""+email+"\"", false);
message.addRecipient(Message.RecipientType.TO, i);
message.setSubject("test");
message.setText("test");
message.setHeader("Content-Type","text/plain;charset=windows-1251");
MimeBodyPart mbp1 = new MimeBodyPart();
FileDataSource fds = new FileDataSource(file);
mbp1.setDataHandler(new DataHandler(fds));
mbp1.setFileName(fds.getName());
Multipart mp = new MimeMultipart();
mp.addBodyPart(mbp1);
System.out.println("[EmailHandler] Attaching the following file to email: " + fds.getName());
message.setContent(mp);
SMTPTransport t = (SMTPTransport)session_m.getTransport("smtp");
t.connect("mail.domainname.com", "main#domainname.com", null);
System.out.println("[EmailHandler] Sending email... ");
t.sendMessage(message, message.getAllRecipients());
file.delete();
Thread.sleep(3000);
}
} else {
System.out.println("[EmailHandler] Folder " + outDir.getName() + " is empty... nothing to attach");
}
} else {
System.out.println("Folder not found... Check the path");
}
In this code the String email is Иванов Александр.
And I kept getting this error
javax.mail.internet.AddressException: Local address contains control or whitespace in string ``Иванов Александр''
So would like to know the ways I can make this string go through.
Thank you.
The outlook uses its address book to map a name to one of the email. That is why it is working fine, if you manually try creating a new email and just put the name. Outlook simply do a lookup in the address book and find out the email address.
However, this is not the same with a java program. The program needs exact email address to send an email. Now there could be many ways to find out email address.
The simplest approach is to store the email address in one of the database table.
If the person is associated with the company's SMTP system/active directory; you could use java smtp API / active directory APIs to find out the email or alias (usually be the part of email id before #) and then create email id to be used into the program to send email.
You need to provide a valid mail address. If you are using a fixed structure for your mails just convert the name to latin characters and append #domain.com
If you are not using any rules for your mail adress creation then I suggest you to add an email field to the database
Don't know if this resolves your question though
Regards
Your program have to
Validate e-mail.
It can be implemented using regular expression: Using a regular expression to validate an email address
Get email from contact list when field contains only name. There are two library for working with outlook contacts:
Open source java library to read outlook emails, calendar etc