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.
Related
I am having a really weird problem when adding more than one MimeBodyPart to a MimeMultiPart. Essentially, if the MimeMultiPart is mixed, then all MimeBodyPart objects are added as attachments, except for the last one, which is added to the body. If the MimeMultiPart is alternative, then only the last MimeBodyPart is added to the body.
I am just trying to write a simple email which should have an opening (text), followed by a table (html), and finally a closing (text).
Code
Here is the code for my function creating the email. It generates the MimeMessage and then opens it in Outlook as a draft.
public void writeEmail() throws Exception {
//Create message envelope.
MimeMessage msg = new MimeMessage((Session) null);
//Set destination and cc
msg.addFrom(InternetAddress.parse("SELECT#ACCOUNT"));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("support#bar.com"));
msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse("manager#baz.com"));
//Create and set the subject
String subject = "subject";
msg.setSubject(subject);
//Make the message as a draft
msg.setHeader("X-Unsent", "1");
//Create the body
MimeMultipart mmp = new MimeMultipart("alternative");
//Tests
String opening = "Opening";
String html = "<h1>" + table + "</h1>";
String closing = "Closing";
MimeBodyPart openingPart = new MimeBodyPart();
openingPart.setDisposition(MimeBodyPart.INLINE);
openingPart.setText(opening, "utf-8");
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setDisposition(MimeBodyPart.INLINE);
htmlPart.setContent(html, "text/html; charset=utf-8");
MimeBodyPart closingPart = new MimeBodyPart();
closingPart.setDisposition(MimeBodyPart.INLINE);
closingPart.setText(closing, "utf-8");
mmp.addBodyPart(openingPart);
mmp.addBodyPart(htmlPart);
mmp.addBodyPart(closingPart);
msg.setContent(mmp);
msg.saveChanges();
//Save as a temporary file
File resultEmail = File.createTempFile("email", ".eml");
try (FileOutputStream fs = new FileOutputStream(resultEmail)) {
msg.writeTo(fs);
fs.flush();
fs.getFD().sync();
}
System.out.println(resultEmail.getCanonicalPath());
ProcessBuilder pb = new ProcessBuilder();
pb.command("cmd.exe", "/C", "start", "outlook.exe", "/eml", resultEmail.getCanonicalPath());
Process p = pb.start();
try {
p.waitFor();
} finally {
p.getErrorStream().close();
p.getInputStream().close();
p.getErrorStream().close();
p.destroy();
}
}
Question
How can I render all the MimeBodyPart as text inside of the email body, instead of them being wrongfully added as attachments?
My below Java class has to copy a text file content and mail to recipients, along with a attached xls file,using java mail.
Now I can read and Mail the text file content but unable to attach the xls file.
Below are my snippet:
static void sendmail() throws IOException,
MessagingException,AddressException,FileNotFoundException
{
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy
HH:mm:ss");
Calendar cal = Calendar.getInstance();
String to1=getOrderinfo.to1;
String to2 = getOrderinfo.to2;
String to3 = getOrderinfo.to3;
String to4 = getOrderinfo.to4;
String from =getOrderinfo.from;
String host = getOrderinfo.host;
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", host);
Session session = Session.getDefaultInstance(properties);
MimeMessage message = new MimeMessage(session);
Multipart multipart = new MimeMultipart();
String pathLogFile = "E:/car_failed_report/log.txt";
try {
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new
InternetAddress(to1));
message.setSubject(" CAR NOT YET INTEGRATED REPORT at
: "+dateFormat.format(cal.getTime()));
StringBuffer sb = new StringBuffer();
FileInputStream fstream = new
FileInputStream(pathLogFile);
BufferedReader br = new BufferedReader(new
InputStreamReader(fstream));
String singleLine;
while ((singleLine = br.readLine()) != null)
{
sb.append(singleLine + "<br>");
// CarParser1.sb1.append(singleLine +"<br>");
}
br.close();
String allLines;
allLines = sb.toString();
String allLines_html=" <html><head><title></title>
</head>"
+ "<body >"+allLines+"</body ></html>";
message.setContent(allLines_html, "text/html;
charset=ISO-8859-1");
MimeBodyPart attachPart = new MimeBodyPart();
File attachement = new File("E:\\car_failed_report
\\failed.xls");
if (attachement.exists()) {
attachPart.attachFile(attachement);
} else {
System.out.println("ERROR READING THE FILE");
throw new FileNotFoundException();
}
Transport.send(message);
System.out.println("Email Sent successfully....");
System.out.println();
}
catch(FileNotFoundException f1)
{
System.out.println("File not yet created..this is from
mailer class");
return;
}
catch (MessagingException mex)
{
System.out.println("Invalid Email Address.please provide
a valid email id to send with");
mex.printStackTrace();
}
Can any one Help me to attach the xls file.?
Thanks in advance.
You created the body part with the attachment but didn't add it to the message. Replace your code starting with message.setContent:
MimeMultipart mp = new MimeMultipart();
MimeBodyPart body = new MimeBodyPart();
body.setText(allLines_html, "iso-8859-1", "html");
mp.addBodyPart(body);
MimeBodyPart attachPart = new MimeBodyPart();
File attachement = new File("E:\\car_failed_report\\failed.xls");
if (attachement.exists()) {
attachPart.attachFile(attachement);
mp.addBodyPart(attachPart);
} else {
System.out.println("ERROR READING THE FILE");
throw new FileNotFoundException();
}
message.setContent(mp);
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);
}
I have here can send mail with multiple attachment:
Properties props = System.getProperties();
String host = "smtp.gmail.com";
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", host);
props.put("mail.smtp.user", from);
props.put("mail.smtp.password", pass);
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
Session session = Session.getDefaultInstance(props);
MimeMessage message = new MimeMessage(session);
Multipart multipart = new MimeMultipart();
// creates body part for the message
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(message, "text/html");
//set message body
BodyPart msgBodyPart = new MimeBodyPart();
msgBodyPart.setText(body);
multipart.addBodyPart(msgBodyPart);
msgBodyPart = new MimeBodyPart();
//attach file
DataSource source = new FileDataSource(attachFile);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(attachFile);
multipart.addBodyPart(messageBodyPart);
//attach file 2
source = new FileDataSource(attachFile2);
BodyPart messageBodyPart2 = new MimeBodyPart();
messageBodyPart2.setDataHandler(new DataHandler(source));
messageBodyPart2.setFileName(attachFile2);
multipart.addBodyPart(messageBodyPart2);
try {
message.setFrom(new InternetAddress(from));
InternetAddress[] toAddress = new InternetAddress[to.length];
// To get the array of addresses
for( int i = 0; i < to.length; i++ ) {
toAddress[i] = new InternetAddress(to[i]);
}
for( int i = 0; i < toAddress.length; i++) {
message.addRecipient(Message.RecipientType.TO, toAddress[i]);
}
} catch (MessagingException ex) {
ex.printStackTrace();
}
message.setSubject(subject);
message.setContent(multipart);
Transport transport = session.getTransport("smtp");
transport.connect(host, from, pass);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
But the problem is how can I add multiple attachments? I don't know if i can declare many variable or put it on array. The code can only include 2 attachments what if 5 or any in every send of the email.
Create a simple method called, something like, attachFile, which takes a File, Multipart and MimeBodyPart as parameters...
public void attachFile(File file, Multipart multipart, MimeBodyPart messageBodyPart) {
DataSource source = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(file.getName());
multipart.addBodyPart(messageBodyPart);
}
Call it as often as you need
File attachFiles[] = ...
if (attachFiles > 0) {
//attach file
attachFile(attachFiles[0], multipart, messageBodyPart);
if (attachFiles > 1) {
for (int index = 1; index < attachFiles.length; index++) {
attachFile(attachFiles[0], multipart, new MimeBodyPart());
}
}
}
as an example
Using Java Mail 1.4 and above makes attaching file more simpler,
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.attachFile(String filePath)
multipart.addBodyPart(messageBodyPart);
Have a look at answer given here
https://stackoverflow.com/a/3177640/772590
Step 1
Create a Datasource
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
Step 2 create method to add attachment
private static void addAttachment(Multipart multipart, String filename)
{
DataSource source = new FileDataSource(filename);
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
}
Step 3 call above method to add attachment
addAttachment(multipart, "file1.txt");
addAttachment(multipart, "file2.txt");
I'm trying to send an email with an attachment. The whole thing works fine, except for the part that the attachment sent sends the attached file with no extension.
For example, sending File.rar will receive file
This is how I'm doing it:
public class EmailSender {
public static void main(String[] args) {
String TO = "Receiver#yahoo.com";
String host = "smtp.gmail.com";
String port = "465";
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties mailConfig = new Properties();
mailConfig.put("mail.smtp.host", host);
mailConfig.put("mail.smtp.socketFactory.port", port);
mailConfig.put("mail.smtp.socketFactory.class", SSL_FACTORY);
mailConfig.put("mail.smtp.auth", "true");
mailConfig.put("mail.smtp.port", port);
Session session = Session.getDefaultInstance(mailConfig,
new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("Username", "Password");
}
});
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from#gmail.com"));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(TO));
message.setSubject("Email with Attachment SUBJECT");
BodyPart messageBodyTxt = new MimeBodyPart();
messageBodyTxt.setText("Email with Attachment BODY");
MimeBodyPart messageBodyAttachment = new MimeBodyPart();
String filePath = "D:\\Unlocker1.9.2.rar";
DataSource source = new FileDataSource(filePath);
messageBodyAttachment.setDataHandler(new DataHandler(source));
messageBodyAttachment.setFileName("Unlocker1.9.2" + ".rar");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyTxt);
multipart.addBodyPart(messageBodyAttachment);
message.setContent(multipart);
Transport.send(message);
System.out.println("Email sent successfully");
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
}
Using the advice from the comment, the proper method would be setDisposition and you would set it for the MimeBodyPart in question. Therefore, with the code above, one would do:
messageBodyAttachment.setDisposition(javax.mail.Part.ATTACHMENT);