Java mail : attach html content along with an attachment - java

I'm trying to send a mail with an attachment and also along with a html content.
I know how to send the html content and the attachments separately but is it possible to send the both the html and as well as the attachment together?
Here's what I've tried :
public static void sendAttachment(final String to, final String cc, final String subject, final String text,
final byte[] attachment, final String fileName) {
if (null == to) {
return;
}
try {
Properties props = getProperties();
Session session = Session.getDefaultInstance(props);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(FROM_EMPRIS));
message.setRecipients(RecipientType.TO, InternetAddress.parse(to));
if(null != cc)
message.addRecipient(RecipientType.CC, new InternetAddress(cc));
if (null != subject)
message.setSubject(subject);
BodyPart messageBodyPart1 = new MimeBodyPart();
messageBodyPart1.setText(text);
BodyPart messageBodyPart2 = new MimeBodyPart();
DataSource ds = new ByteArrayDataSource(attachment, "application/x-any");
messageBodyPart2.setDataHandler(new DataHandler(ds));
messageBodyPart2.setFileName(fileName);
Multipart multiPart = new MimeMultipart();
multiPart.addBodyPart(messageBodyPart1);
multiPart.addBodyPart(messageBodyPart2);
message.setContent(multiPart);
Transport.send(message);
} catch (AddressException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
This one sends the attachment and the setText(text) as a plaintext. Can this be changed to a html content instead of a plaintext?
Would greatly appreciate your help and thanks a lot.

Just create another mimeBodyPart with html content and setContent(htmlContent, "text/html"). Add that after your plain text body part.

Use below method and set html content in body
message.setContent(body,"text/html");

Set DataHandler for messageBodyPart1
BodyPart messageBodyPart1 = new MimeBodyPart();
messageBodyPart1.setText(text);
messageBodyPart1.setDataHandler(new DataHandler(textHtml, "text/html;charset=utf-8"));// this is to handle html

Related

Sending string as an attachment using javamail gets duplicated content

I'm struggling to send a csv file over javamail.
Since the content is small, I constructed manually the data as CSV format, stored in memory and passed as ByteArrayDataSource to MimeMessageHelper. However, the received file has strangely double the content.
The code is pretty standard:
// mail sender
try {
MimeMessage mail = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mail, true, "UTF-8");
helper.setSubject(mailObj.getMailSubject());
helper.setFrom(mailObj.getMailFrom());
helper.setTo(mailObj.getMailTo());
Mail.Attachment attachment = mailObj.getAttachment();
if (attachment != null) helper.addAttachment(attachment.getFilename(),
attachment.getDataSource());
javaMailSender.send(helper.getMimeMessage());
} catch (Exception e) {
log.error("Cannot send email " + mailObj.toString(), e);
}
DataSource createDataSource(Data originalData) throws IOException {
try (StringWriter out = new StringWriter(); PrintWriter pw = new PrintWriter(out) {
#Override
public void println() {
write(LINE_SEP);
}
}) {
pw.write('\uFEFF'); // Write BOM
pw.println(HEADERS);
for (AppointmentBookingEvent details : appointments) {
// Concatenate the data with PrintWriter.println(...);
}
return new ByteArrayDataSource(out.toString().getBytes(StandardCharsets.UTF_8), "text/csv");
}
}
I noticed that the method DataSource.getInputStream() is called twice by the sender's internal functions. Was that by any chance the cause ?
It seems the problem came from MimeMessageHelper. I could not figure exactly where but the problem has gone when I explicitly constructed the body parts of mail.
MimeMessage mail = javaMailSender.createMimeMessage();
mail.setFrom(new InternetAddress(mailObj.getMailFrom()));
mail.setRecipients(Message.RecipientType.TO, InternetAddress.parse(mailObj.getMailTo()));
mail.setSubject(mailObj.getMailSubject());
Multipart multipart = new MimeMultipart();
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(getContentFromTemplate(mailObj.getModel(), mailObj.getLang(), mailObj.getTemplateName()), "text/html; charset=UTF-8");
multipart.addBodyPart(messageBodyPart);
Mail.Attachment attachment = mailObj.getAttachment();
if (attachment != null) {
BodyPart attachmentBodyPart = new MimeBodyPart();
attachmentBodyPart.setFileName(attachment.getFilename());
attachmentBodyPart.setDisposition(Part.ATTACHMENT);
attachmentBodyPart.setDataHandler(new DataHandler(attachment.getDataSource()));
multipart.addBodyPart(attachmentBodyPart);
}
mail.setContent(multipart);
javaMailSender.send(mail);

GWT Java email - java.io.UnsupportedEncodingException: text/html

I am sending an email with html text and an attachment and getting the error:
java.io.UnsupportedEncodingException: text/html
The code is:
public void emailMessage(String emailSubject, String message, String emailaddress, String imagePath) {
//Send an email
try {
//Send an email
SimpleEmail email = new SimpleEmail();
email.setHostName("mail.org");
email.setSmtpPort(25); //No authentication required
email.setFrom("address.org");
email.addTo(emailaddress);
email.setSubject(emailSubject);
email.setCharset("utf-8");
// Set the email message text.
MimeBodyPart messagePart = new MimeBodyPart();
messagePart.setText(message, "text/html");
// Set the email attachment file
FileDataSource fileDataSource = new FileDataSource(imagePath);
MimeBodyPart attachmentPart = new MimeBodyPart();
attachmentPart.setDataHandler(new DataHandler(fileDataSource));
attachmentPart.setFileName(fileDataSource.getName());
// Create Multipart E-Mail.
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(messagePart);
multipart.addBodyPart(attachmentPart);
email.setContent(multipart);
//Send the email
email.send();
} catch (EmailException e) {
e.printStackTrace();
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Initially I was sending an email without an attachment which worked. Then I added the multipart for the attachment and the text/html is no longer valid.
Try
textPart.setText(text, "utf-8" );
or
htmlPart.setContent(html, "text/html; charset=utf-8" );
This worked for me with java >= 8:
MimeMessage msg = new MimeMessage(session)
msg.setContent(content, "text/html")
use setContent instead setText

Create multipart using JavaMail

I would like to create a MimeMessage which must have two parts as shown below picture (Part_0 and Part_2)
I'm trying to use below code to generated s/mime
public static void main(String[] a) throws Exception {
// create some properties and get the default Session
Properties props = new Properties();
// props.put("mail.smtp.host", host);
Session session = Session.getInstance(props, null);
// session.setDebug(debug);
MimeMessage msg = new MimeMessage(session);
try {
msg.addHeader("Content-Type", "multipart/signed; protocol=\"application/pkcs7-signature;");
msg.setFrom(new InternetAddress(FROM_EMAIL));
InternetAddress[] address = {new InternetAddress(
TO_EMAIL)};
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("Test Subject");
msg.setSentDate(new Date());
// create and fill the first message part
MimeBodyPart bodyPart1 = new MimeBodyPart();
bodyPart1.setHeader("Content-Type", "text/html; charset=utf-8");
bodyPart1.setContent("<b>Hello World</b>", "text/html");
Multipart multiPart = new MimeMultipart();
multiPart.addBodyPart(bodyPart1, 0);
try (OutputStream str = Files.newOutputStream(Paths
.get(UNSIGNED_MIME))) {
bodyPart1.writeTo(str);
}
signMime();
MimeBodyPart attachPart = new MimeBodyPart();
String filename = SIGNED_VALUE;
DataSource source = new FileDataSource(filename);
attachPart.setDataHandler(new DataHandler(source));
attachPart.setFileName("smime.p7s");
attachPart.addHeader("Content-Type", "application/pkcs7-signature; name=smime.p7s;");
attachPart.addHeader("Content-Transfer-Encoding", "base64");
attachPart.addHeader("Content-Description", "S/MIME Cryptographic Signature");
multiPart.addBodyPart(attachPart);
msg.setContent(multiPart, "multipart/signed; protocol=\"application/pkcs7-signature\"; ");
msg.saveChanges();
try (OutputStream str = Files.newOutputStream(Paths
.get(SIGNED_MIME))) {
msg.writeTo(str);
}
} catch (MessagingException mex) {
mex.printStackTrace();
Exception ex = null;
if ((ex = mex.getNextException()) != null) {
ex.printStackTrace();
}
}
I used two MimeBodyPart however I always got one Part_0 and generated eml file shown below.
I haven't tried to compile it, but what you want is something like this. The inner multipart is a body part of the outer multipart.
msg.setFrom(new InternetAddress(FROM_EMAIL));
InternetAddress[] address = {new InternetAddress(
TO_EMAIL)};
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("Test Subject");
msg.setSentDate(new Date());
MultipartSigned multiSigned = new MultipartSigned();
// create and fill the first message part
MimeBodyPart bodyPart1 = new MimeBodyPart();
bodyPart1.setText("<b>Hello World</b>", "utf-8", "html");
Multipart multiPart = new MimeMultipart();
multiPart.addBodyPart(bodyPart1);
// add other content to the inner multipart here
MimeBodyPart body = new MimeBodyPart();
body.setContent(multiPart);
multiSigned.addBodyPart(body);
try (OutputStream str = Files.newOutputStream(Paths
.get(UNSIGNED_MIME))) {
body.writeTo(str);
}
signMime();
MimeBodyPart attachPart = new MimeBodyPart();
String filename = SIGNED_VALUE;
attachPart.attachFile(filename,
"application/pkcs7-signature; name=smime.p7s", "base64");
attachPart.setFileName("smime.p7s");
attachPart.addHeader("Content-Description",
"S/MIME Cryptographic Signature");
multiSigned.addBodyPart(attachPart);
msg.setContent(multiSigned);
msg.saveChanges();
And you'll need this:
public class MultipartSigned extends MimeMultipart {
public MultipartSigned() {
super("signed");
ContentType ct = new ContentType(contentType);
ct.setParameter("protocol", "application/pkcs7-signature");
contentType = ct.toString();
}
}
You could make this much cleaner by moving more of the functionality into the MultipartSigned class.
What you are looking for is Spring Mime Helper.

Send HTML email along with multiple file attachments?

I am trying to send an HTML email in the body of an email along with few file attachments as well. I came up with below code:
public void sendEmail(final String to, final String from, final String cc, final String subject, final String body,
final String baseDirectory, final List<String> listOfFileNames) {
for (int i = 1; i <= 3; i++) { // retrying
try {
Session session = Session.getInstance(mailProperties, null);
Multipart multipart = new MimeMultipart();
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
InternetAddress[] toAddress = InternetAddress.parse(to);
InternetAddress[] ccAddress = InternetAddress.parse(cc);
message.addRecipients(RecipientType.TO, toAddress);
message.addRecipients(RecipientType.CC, ccAddress);
message.setSubject(subject);
message.setContent(body, "text/html;charset=utf8");
for (String file : listOfFileNames) {
String fileLocation = baseDirectory + "/" + file;
addAttachment(multipart, fileLocation);
}
message.setContent(multipart);
Transport.send(message, toAddress);
break;
} catch (Exception ex) {
// log exception
}
}
}
// this is used for attachment
private void addAttachment(final Multipart multipart, final String filename) throws MessagingException {
DataSource source = new FileDataSource(filename);
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
}
I need to have body String as part of my HTML email and have all the files attach in the same email. I am running like this as in my home directory, I have two files: abc.csv and tree.txt.
EmailTest.getInstance().sendEmail("hello#host.com", "hello#host.com", "hello#host.com",
"Test Subject (" + dateFormat.format(new Date()) + ")", content, "/export/home/david/",
Arrays.asList("abc.csv", "tree.txt"));
After I get an email, I don't see my text in the body of an email at all? And second thing is file attachment name is coming as /export/home/david/abc.csv and /export/home/david/tree.txt?
Is anything wrong I am doing? One thing I see wrong as I am calling setContent method twice with different parameters?
First you need to add the text as an own BodyPart. Next your MimeMultipart needs to be set to the type related so you can have both, HTML-Text and some attachements. Then it should work to have both, attachements and text.
And the filename you pass to messageBodyPart.setFileName(filename) is the filename you see in the attachment name. So just leave out the path and you should just see abc.csv and tree.txt
public void sendEmail(final String to, final String from, final String cc, final String subject, final String body,
final String baseDirectory, final List<String> listOfFileNames) {
for (int i = 1; i <= 3; i++) { // retrying
try {
Session session = Session.getInstance(mailProperties, null);
Multipart multipart = new MimeMultipart("related");
MimeBodyPart bodyPart= new MimeBodyPart();
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
InternetAddress[] toAddress = InternetAddress.parse(to);
InternetAddress[] ccAddress = InternetAddress.parse(cc);
message.addRecipients(RecipientType.TO, toAddress);
message.addRecipients(RecipientType.CC, ccAddress);
message.setSubject(subject);
bodyPart.setText(body, "UTF-8", "html");
multipart.addBodyPart(bodyPart);
for (String file : listOfFileNames) {
String fileLocation = baseDirectory + "/" + file;
addAttachment(multipart, fileLocation, file);
}
message.setContent(multipart);
Transport.send(message, toAddress);
break;
} catch (Exception ex) {
// log exception
}
}
}
// this is used for attachment
private void addAttachment(final Multipart multipart, final String filepath, final String filename) throws MessagingException {
DataSource source = new FileDataSource(filepath);
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
}

Sending mail via Java API: How to send the mail even if attachment fails?

This is my code:
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(messageSubject);
message.setText(messageBody);
BodyPart messageBodyPart1 = new MimeBodyPart();
messageBodyPart1.setText(messageBody);
MimeBodyPart messageBodyPart2 = new MimeBodyPart();
String filename = attachment;
DataSource source = new FileDataSource(filename);
messageBodyPart2.setDataHandler(new DataHandler(source));
messageBodyPart2.setFileName(filename);
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart1);
multipart.addBodyPart(messageBodyPart2);
message.setContent(multipart );
Transport.send(message);
} catch (MessagingException mex) {
mex.printStackTrace();
}
How can I still send the email even if mail attachment fails for some reason? ATM if attachment fails, the email is not sent, which is bad in my case.
Should I use another try/catch statement and should I have finally as well?
Im new to Java (3-4 weeks)
edit:
Changed my code to this, but didnt work
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(messageSubject);
message.setText(messageBody);
try {
BodyPart messageBodyPart1 = new MimeBodyPart();
messageBodyPart1.setText(messageBody);
MimeBodyPart messageBodyPart2 = new MimeBodyPart();
String filename = attachment;
DataSource source = new FileDataSource(filename);
messageBodyPart2.setDataHandler(new DataHandler(source));
messageBodyPart2.setFileName(filename);
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart1);
multipart.addBodyPart(messageBodyPart2);
message.setContent(multipart);
} catch (Exception e) {
message.setText(messageBody2);
e.printStackTrace();
}
Transport.send(message);
} catch (MessagingException mex) {
mex.printStackTrace();
}
Yes. I would expect to be able to do (pseudo-code follows)
try {
// set up standard message
try {
// perform attachment
}
catch {
// perhaps amend your original message to indicate attachment failed
}
send();
}
catch {
// handle a complete failure here...
}
although I'd concentrate on why the attachment fails. Does that even make sense ?
You may take the approach of building/sending in two different methods, such that you don't have to clean up / modify your message in the face of a failure. That may be a cleaner approach e.g. (pseudo-code again)
try {
sendMessageWithAttachment();
}
catch {
sendMessageWithoutAttachment();
}

Categories