Java Mail - Attachments not showing in email clients? - java

Ok so I'm having to alter some old code from another dev that he sent up for sending emails from our app with Java Mail. This has worked fine for a long time but now we are required to send pdf attachments as well.
So basically below, assume there is an object "mail" that has getters for the text and html messages as well as now a getter for the pdf filename to load from the filesystem and attach to the mail.
I've altered the below code where marked, so if there is a pdf to attach, load from filesystem and attach. I've tried to use the same structure as the previous code, although I suspect its not all required?
Multipart mp = new MimeMultipart("alternative");
// Create a "text" Multipart message
BodyPart textPart = new MimeBodyPart();
textPart.setContent(mail.getText(), "text/plain");
mp.addBodyPart(textPart);
// Create a "HTML" Multipart message
Multipart htmlContent = new MimeMultipart("related");
BodyPart htmlPage = new MimeBodyPart();
htmlPage.setContent(mail.getHtml(), "text/html; charset=UTF-8");
htmlContent.addBodyPart(htmlPage);
BodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(htmlContent);
mp.addBodyPart(htmlPart);
// NEW CODE STARTS HERE
if(StringUtils.isNotBlank(mail.getPdfAttachmentFileName())) {
Multipart pdfContent = new MimeMultipart("mixed"); //<---- this appears to be an issue???
BodyPart pdfPage = new MimeBodyPart();
File file = new File(uploadDir + "/" + mail.getPdfAttachmentFileName());
DataSource dataSource = new ByteArrayDataSource(new FileInputStream(file), "application/pdf");
pdfPage.setDataHandler(new DataHandler(dataSource));
pdfPage.setFileName(mail.getPdfAttachmentFileName());
pdfContent.addBodyPart(pdfPage);
BodyPart pdfPart = new MimeBodyPart();
pdfPart.setContent(pdfContent);
mp.addBodyPart(pdfPart);
}
// NEW CODE ENDS HERE
mimeMessage.setContent(mp);
At any rate, the above works, sort of. There are no errors or exceptions and the message gets sent. BUT the attachment doesn't appear depending on which email client you recieve the mail with.
With the code as above, Outlook receives the message as readable and the attachment is visible and downloadable. This is perfect. BUT in GMail, the message is still readable, the paperclip appears to indicate there is an attachment, but there is no attachment to download?
If you switch the `Multipart pdfContent = new MimeMultipart("mixed");' to be "related" rather than "mixed" the exact opposite is true. GMail receives it perfectly but Outlook only gets the message and paperclip, no actual attachment.
Obviously we need to be sending emails to our customers with no knowledge of their email client used to open them! Obviously I'm a novice at Java Mail so have simply copied suggested code but this isn't gelling well with our existing code!
Any ideas how to alter the above to make it completely email client independant?

Ok turns out Spring has a helper class to hide all this mess away from you.
I've refactored all of the above code into the following and it works great;
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setTo(mail.getTo());
message.setFrom(mail.getFrom());
message.setSubject(mail.getSubject());
message.setText(mail.getText(), mail.getHtml());
if(StringUtils.isNotBlank(mail.getPdfAttachmentFileName())) {
File file = new File(uploadDir + "/" + mail.getPdfAttachmentFileName());
DataSource dataSource = new ByteArrayDataSource(new FileInputStream(file), "application/pdf");
message.addAttachment(mail.getPdfAttachmentFileName(), dataSource);
}

Related

Use Java Gmail API to send an email with multiple (large) attachments

I am trying to use the Google Gmail API (Java) to create an email that contains multiple attachments. Using the code below, I am able to send multiple attachments that are embedded within a MimeMessage if the attachments total less than 5MB (Google's threshold for simple file upload).
com.google.api.services.gmailGmail service = (... defined above ...)
javax.mail.internet.MimeMessage message = (... defined above with attachments embedded ...)
// Send the email
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
mimeMessage.writeTo(buffer);
byte[] bytes = buffer.toByteArray();
String encodedEmail = Base64.encodeBase64URLSafeString(bytes);
Message message = new Message();
message.setRaw(encodedEmail);
message = service.users().messages().send("me", message).execute();
However, I am unable to figure out how to correctly attach multiple files to an email using the Gmail Java API. The method below looks promising, but it appears to only accept 1 File/InputStream (mediaContent).
Gmail.Users.Messages.Send send(userId, Message content, AbstractInputStreamContent mediaContent)
Anyone know how to correctly implement a multi-file upload using the API?
As you correctly stated, the maximum attachment size for Simple file upload is 5 MB
Conclusion:
You need to to use Multipart upload or Resumable upload.
A sample sending an email with a multipart upload:
public static MimeMessage createEmailWithAttachment(String to, String from, String subject,
String bodyText,String filePath) throws MessagingException{
File file = new File(filePath);
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
Multipart multipart = new MimeMultipart();
InternetAddress tAddress = new InternetAddress(to);
InternetAddress fAddress = new InternetAddress(from);
email.setFrom(fAddress);
email.addRecipient(javax.mail.Message.RecipientType.TO, tAddress);
email.setSubject(subject);
if (file.exists()) {
source = new FileDataSource(filePath);
messageFilePart = new MimeBodyPart();
messageBodyPart = new MimeBodyPart();
try {
messageBodyPart.setText(bodyText);
messageFilePart.setDataHandler(new DataHandler(source));
messageFilePart.setFileName(file.getName());
multipart.addBodyPart(messageBodyPart);
multipart.addBodyPart(messageFilePart);
email.setContent(multipart);
} catch (MessagingException e) {
e.printStackTrace();
}
}else
email.setText(bodyText);
return email;
}
Here you can find many other useful samples for sending emails with the Gmail API in Java.
It turns out that my MimeMessage was generated correctly, however, if the attachments included in the MimeMessage are larger than 5MB, you need to use a different Gmail API send() method. The API docs are incredibly confusing because they appear to state that you need to make multiple calls to rest endpoints to upload multiple files. It turns out that the Gmail Java Api does all the for you based off the MimeMessage submitted.
Below is a code snippet that shows how to use the two methods: "simple upload" and "multipart upload".
com.google.api.services.gmailGmail service = (... defined above ...)
javax.mail.internet.MimeMessage message = (... defined above with attachments embedded ...)
/**
* Send email using Gmail API - dynamically uses simple or multipart send depending on attachments size
*
* #param mimeMessage MimeMessage (includes any attachments for the email)
* #param attachments the Set of files that were included in the MimeMessage (if any). Only used to calculate total size to see if we should use "simple" send or need to use multipart upload.
*/
void send(MimeMessage mimeMessage, #Nullable Set<File> attachments) throws Exception {
Message message = new Message();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
mimeMessage.writeTo(buffer);
// See if we need to use multipart upload
if (attachments!=null && computeTotalSizeOfAttachments(attachments) > BYTES_5MB) {
ByteArrayContent content = new ByteArrayContent("message/rfc822", buffer.toByteArray());
message = service.users().messages().send("me", null, content).execute();
// Otherwise, use "simple" send
} else {
String encodedEmail = Base64.encodeBase64URLSafeString(buffer.toByteArray());
message.setRaw(encodedEmail);
message = service.users().messages().send("me", message).execute();
}
System.out.println("Gmail Message: " + message.toPrettyString());
}

why the reply mail is sent as attachment when I send it to outlook account using javamail?

I tried in many ways to get the reply in same thread using outlook account and javamail api but iam not able to get reply in same thread instead iam getting as attachment.
I tried to copy whole content and save in current message even then iam getting as attachment, also tried to change the content disposition as inline still it didn't work
you can find the code below which i had tried.
Properties properties = new Properties();
Session emailSession = Session.getDefaultInstance(properties,null);
store = emailSession.getStore("imaps");
store.connect(host,mailbox_username, mailbox_password);
folder = store.getFolder("Inbox");
folder.open(Folder.READ_WRITE);
Message[] unreadMessages = folder.search(new FlagTerm(new Flags(Flags.Flag.SEEN),false));
if(unreadMessages.size()>0)
{
for (int i = 0; i < unreadMessages.length; i++)
{
log.info("retriving message "+(i+1))
Message message = unreadMessages[i]
Address[] froms = message.getFrom();
String senderEmailAddress =(froms[0]).getAddress();
if(senderEmailAddress.endsWith("#gmail.com"))
{
subject = message.getSubject()
log.info(message.getSubject())
}
else
{ //reply to same mail here we need to reply to the message
Message message2 = new MimeMessage(emailSession);
message2= (MimeMessage) message.reply(false);
message2.setSubject("RE: " + message.getSubject());
//message2.setFrom(new InternetAddress(from));
message2.setReplyTo(message.getReplyTo());
message2.addRecipient(Message.RecipientType.TO, new InternetAddress(senderEmailAddress));
BodyPart messageBodyPart = new MimeBodyPart();
content = "some reply message"
//multipart.addBodyPart(content);
messageBodyPart.setText(content);
Multipart multipart = new MimeMultipart("related");
multipart.addBodyPart(messageBodyPart);
messageBodyPart = new MimeBodyPart();
//messageBodyPart.setDataHandler(message.getDataHandler());
//bodyPart.setDataHandler(new DataHandler(ds));
//messageBodyPart.setHeader("Content-Type", "image/jpeg; name=image.jpg");
//messageBodyPart.setHeader("Content-ID", "<image>");
//messageBodyPart.setHeader("Content-Disposition", "inline");
//messageBodyPart.addBodyPart(bodyPart);
//msg.setContent(content);
messageBodyPart.setDisposition(MimeBodyPart.INLINE);
messageBodyPart.setContent(message, "message/rfc822");
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
message2.setContent(multipart);
Transport t = emailSession.getTransport("smtp");
try {
t.connect(mailbox_username, mailbox_password);
t.sendMessage(message2, message2.getAllRecipients());
} finally {
t.close();
}
}
}
}
"inline" vs. "attachment" is just advice for the mail reader. Many ignore the device, or aren't capable of displaying all content types inline.
If you want the text of the original message to appear in the body of the reply message (e.g., indented with ">"), you need to extract the original text and reformat it appropriately, adding it to the text of the reply, then set that new String as the content of the reply message.

Email attachment sent via smtp to iphone are not visible in iphone native email app

I have a web service that sends an email with attachments.
the code snippet that sends email is
MimeMultipart content = new MimeMultipart("related");
msg.setContent(content);
MimeBodyPart attachment = new MimeBodyPart();
File file = new File("filename.txt");
String fileName = "";
DataSource fds;
String fullPathFile = mail.getAttachment().get(i);
String pathArray[] = fullPathFile.split("/");
fds = new FileDataSource(file);
attachment.setDataHandler(new DataHandler(fds));
attachment.setHeader("Content-ID", "<" + id + ">");
attachment.setFileName(fds.getName());
content.addBodyPart(attachment);
This works fine for every email app. But in the native iPhone email app, I am unable to view the attachment.
In the image, we can see the attachment icon but when I open the email, I find no attachments
I also referred the link:
https://discussions.apple.com/thread/7491137?start=30&tstart=0
Is there a programing solution for this?
The way you attache the MimeBodyPart is causing this issue. I had the same problem. Your fix would look like:
attachments = new MimeBodyPart();
DataSource source = new FileDataSource(dest);
attachments.setDataHandler(new DataHandler(source));
attachments.setFileName(source.getName());
mp.addBodyPart(attachments);
Multipart htmlAndTextMultipart = new MimeMultipart("alternative");
MimeBodyPart htmlBodyPart = new MimeBodyPart();
htmlBodyPart.setContent(body, "text/html; charset=utf-8");
htmlAndTextMultipart.addBodyPart(htmlBodyPart);
MimeBodyPart htmlAndTextBodyPart = new MimeBodyPart();
htmlAndTextBodyPart.setContent(htmlAndTextMultipart);
mp.addBodyPart(htmlAndTextBodyPart);

html email with reference to an image as base64 String

I would like to send an email with the Java Mail API (javax.mail). The message must contain html and inside there is a reference to an image. There is a challenge, because no reference to a physical file on disk is allowed but instead I have created a base64 string (http://www.base64-image.de/step-1.php) for that image and copied that data to a static String variable.
With javax.mail I build a message of type MulitPart with two parts. The first part is the html itself and the second part is the image. The html part reference to the image via <img src="cid:image-id"/>.
Message msg = new MimeMessage(session);
Multipart multipart = new MimeMultipart("related");
BodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<html><body><h2>A title</h2>Some text in here<br/>" +
"<img src=\"cid:the-img-1\"/><br/> some more text<img src=\"cid:the-img-1\"/></body></html>", "text/html");
multipart.addBodyPart(htmlPart);
public static final String base64logo = "/9j/4AAQSkZJRgABAQEASABIAAD/4QBe…"; // ein ganz langer String erzeugt über http://www.base64-image.de/step-1.php
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
byte[] imageByte = decoder.decodeBuffer(base64logo);
InternetHeaders header = new InternetHeaders();
BodyPart imgPart=new MimeBodyPart(header, imageByte);
imgPart.setHeader("Content-ID","the-img-1");
imgPart.setDisposition(MimeBodyPart.INLINE);
multipart.addBodyPart(imgPart);
msg.setContent(multipart);
Unfortunately the image is missing in the incoming email.
When I point to the file on my disk it is working:
DataSource ds=new FileDataSource("c:/temp/image001.jpg");
imgPart.setDataHandler(new DataHandler(ds));
We are developing with Talend and we cannot reference
to external files because that would make the deployment process
more complicate.
Can you find some wrong doings in my approach?
Kind regards
Hilderich
Try putting angle braces here
imgPart.setHeader("Content-ID","<the-img-1>");
I found this answer on the comments of an old post from this blog
http://www.jroller.com/eyallupu/entry/javamail_sending_embedded_image_in
In the comment of Aravind Velayudhan Nair
It worked for me!
This has been asked before a long time ago. But I will answer this as I have faced the same issue, from my own answer here.
byte[] tile = DatatypeConverter.parseBase64Binary(base64logo);
BodyPart messageBodyPart = new MimeBodyPart();
DataHandler dataHandler = new DataHandler(new ByteArrayDataSource(tile, "image/jpeg"));
messageBodyPart.setDataHandler(dataHandler);
messageBodyPart.setHeader("Content-ID", "<the-img-1>");
multipart.addBodyPart(messageBodyPart);
msg.setContent(multipart);
Hope it will help someone.

How do I send mail with both plain text as well as HTML text so that each mail reader can choose the format appropriate for it?

From http://www.oracle.com/technetwork/java/faq-135477.html#sendmpa:
You'll want to send a MIME multipart/alternative message. You
construct such a message essentially the same way you construct a
multipart/mixed message, using a MimeMultipart object constructed
using new MimeMultipart("alternative"). You then insert the text/plain
body part as the first part in the multpart and insert the text/html
body part as the second part in the multipart. You'll need to
construct the plain and html parts yourself to have appropriate
content. See RFC2046 for details of the structure of such a message.
Can someone show me some sample code for this?
This is a part of my own code:
final Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(senderAddress, senderDisplayName));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress(m.getRecipient(), m.getRecipientDisplayName()));
msg.setSubject(m.getSubject());
// Unformatted text version
final MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(m.getText(), "text/plain");
// HTML version
final MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(m.getHtml(), "text/html");
// Create the Multipart. Add BodyParts to it.
final Multipart mp = new MimeMultipart("alternative");
mp.addBodyPart(textPart);
mp.addBodyPart(htmlPart);
// Set Multipart as the message's content
msg.setContent(mp);
LOGGER.log(Level.FINEST, "Sending email {0}", m);
Transport.send(msg);
Where m is an instance of my own class.

Categories