I have a MailMessage class I've written to manage sending email from my application. It works fine for plain text messages, and the attachment logic works when I compile and run it manually on the command line, but it fails to include my attachments when I'm running it within Glassfish 3.1. I'm assuming there must be some subtle class loading problem that I'm clobbering on the command line by having my CLASSPATH environment set, but I haven't been able to figure out what application server setting I need to change. Here's the code I use to create and send my mail message when running on the command line:
public static void main(String[] args) throws Exception {
String[] toAddr = new String[] {"steve.ferguson#epsilon.com"};
String subject = "This is a test";
String data = "This is a message body";
MailMessage mailMessage = new MailMessage(toAddr, subject, data);
mailMessage.addAttachment(new File("/etc/hosts"), "text/plain");
mailMessage.send();
}
If I change this function to a method called by my servlet, with debugging enabled, the resulting mail message looks like this:
[#|2011-11-17T11:21:37.710-0500|INFO|glassfish3.1|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=105;_ThreadName=Thread-1;|Date: Thu, 17 Nov 2011 11:21:37 -0500 (EST)
From: sender#mydomain.com
To: steve.ferguson#mydomain.com
Message-ID: <9116840.7.1321546897580.JavaMail...>
Subject: This is a test
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_6_16232037.1321546897569"
.
|#]
By comparison, when I run the same code on the command line, it shows all of the attachments, each with the separate message boundary. This is the function I'm using to add the attachments to the underlying MimeMessage:
private Multipart buildMultipartMessage(String messageBody)
throws MessagingException {
MimeBodyPart messagePart = new MimeBodyPart();
messagePart.setText(messageBody.toString());
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messagePart);
// Attach each of our files
for (File part : attachment.keySet()) {
BodyPart attachmentPart = new MimeBodyPart();
attachmentPart.setDataHandler(new DataHandler(new FileDataSource(part)));
attachmentPart.setFileName(part.getName() + ".txt");
attachmentPart.setHeader("Content-Type", attachment.get(part));
attachmentPart.setHeader("Content-ID", part.getName());
attachmentPart.setDisposition(Part.ATTACHMENT);
multipart.addBodyPart(attachmentPart);
}
return multipart;
}
Which is called and used like this by my MailMessage class:
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("sender#mydomain.com"));
InternetAddress[] addresses = new InternetAddress[mailTo.length];
for (int i = 0; i < mailTo.length; i++)
addresses[i] = new InternetAddress(mailTo[i]);
message.setRecipients(Message.RecipientType.TO, addresses);
message.setSubject(subject);
message.setSentDate(new Date());
Multipart multipart = buildMultipartMessage(messageBody.toString());
message.setContent(multipart);
Again, all of this code, exactly as is, compiles, runs, and produces a valid email with attachments when run on the command line. It's only when I do the same thing within Glassfish that I get an empty message.
Any suggestions on how to diagnose this would be most appreciated.
Steve
UPDATE:
If I add this code after the call to buildMultipartMessage(), but before message.setContent(multipart), I can see that the content is correct:
try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/var/tmp/stf"));
multipart.writeTo(bos);
bos.close();
} catch (Exception ex) { }
The /var/tmp/stf file contains the full message body with attachments and separators. I'm still confused as to why this works from the command line, but not within Glassfish, but the information may be useful in resolving the problem.
It turned out that my solution to this problem caused the current problem. Having javax.mail.jar in my boot classpath and activation.jar in my endorsed directory was the only way I could get email handling working with the logger, but then they didn't work for normal usage. I have no idea why this is, but I found that eliminating the -Xbootclasspath option and removing activation.jar from my endorsed directory fixed the problem. If anyone has any speculation as to why, I'd be glad to do some more testing and report back. For now, I guess I have to live without email logging, because the attachments are a requirement for my application.
Perhaps if I switch to log4j instead of using the native Java EE 6 logging, I can have the best of both worlds.
Related
I'm having an issue with sending attachments via email in java using the java mail (1.4.6). It seems that when I attach a document of any sort and send it, the recipient gets the file in plain text format in the body. Rather than, you guessed it, sending the whole file like you would expect and the body not interfered with.
Code
try
{
// Create a message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(username));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(Compose.to));
message.setSubject(Compose.subject);
//message.setText(Compose.body);
//If there are no CC's then skip it. This if seemed to decrease send time.
if(Compose.cc != null)
{
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(Compose.cc));
message.saveChanges();
}
else
message.saveChanges();
/*
* For adding the attached file to the email. This time the if
* statement is used to stop the email attachment process if there
* is none. Other wise due to the way I've set it up it'll try to
* send file path and file name as null, and we fail an otherwise valid email.
*/
if(Compose.filename != null)
{
String file = Compose.filepath;
String fileName = Compose.filename;
Multipart multipart = new MimeMultipart();
BodyPart messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(fileName);
multipart.addBodyPart(messageBodyPart);
BodyPart messageBodyPart2 = new MimeBodyPart();
messageBodyPart2.setText(Compose.body);
multipart.addBodyPart(messageBodyPart2);
message.setContent(multipart);
}
else
{
message.setText(Compose.body);
message.saveChanges();
}
//Send the message by javax.mail.Transport .
Transport tr = session.getTransport("smtp"); // Get Transport object from session
tr.connect(smtphost, username, password); // We need to connect
tr.sendMessage(message, message.getAllRecipients()); // Send message
//Notify the user everything functioned fine.
JOptionPane.showMessageDialog(null, "Your mail has been sent.");
}
Thinking over this I remembered how FileDataSource() is an overloaded statement taking a string or a file type as a parameter, trying both I got the same result but I will experiment more with the the file type now.
EDIT: After more testing I noticed that sometimes the file will not appear along with whatever was in the body at the time of sending.
For each part you have to set disposition to Part.INLINE for the body and Part.ATTACHMENT for the attachment. The attachFile methods will do that for you. Avoid JavaMail 1.4.6 in favor of the latest release or at least use JavaMail 1.4.7 which contains fixes for known issues with JavaMail 1.4.6.
You're setting the attachment as the first body part. It needs to be the second body part.
Also, consider upgrading to JavaMail 1.5.4 and using the MimeBodyPart.attachFile method to attach the file.
I am use this class to send mail it works but now i wants to add attachment how to add it please help if u can
public static void sendMail(String subject, String body, String toEmail, String ccEmail, String fromMail)
throws IOException {
Random generator = new Random();
int r = Math.abs(generator.nextInt());
body = body.replaceAll("(\\r|\\n)", "");
body = body.replaceAll("\"", "\\\\\"");
body = body.replaceAll("&", "\\\\&");
body = body.replaceAll("©", "\\\\©");
//body = body.replaceAll("> <", ">\\\n<");
if(CommonUtils.emptyString(fromMail))
fromMail = "No Reply <iotasol#pcc.com>";
else
fromMail = "No Reply <"+fromMail+">";
ProcessBuilder processBuilder = new ProcessBuilder(
ApplicationProperties.MAIL_SENDER_SH_PATH, CommonUtils.getEmptyStringForNull(subject), CommonUtils.getEmptyStringForNull(body),
toEmail, ccEmail, String.valueOf(r), fromMail);
processBuilder.start();
}
as an idea if you need to send images: make it inline with base64.
Attachments depends on library used, mail server used and so on.
MimeBodyPart messageBodyPart = new MimeBodyPart();
File file = new File("somefile.txt");
if (file.exists()) {
DataSource source = new FileDataSource("somefile.txt");
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(file.getName());
multipart.addBodyPart(messageBodyPart);
}
From your code example, I can tell that you are using external mail program for sending emails. You create a ProcessBuilder and invoke an OS tool for sending emails.
I would not use this solution. First, it depends on the OS (on windows you don't have the mail command). Second, this is not efficient; since you create external process for this (imagine sending many emails).
Instead, try using existing mail solution in java (you will need: mail.jar and activation.jar). With it you can send emails directly from your application, not depending on external tool.
While with mail Java library you can do everything you want, you may also look at Jodd Email. This is a small, but convenient wrapper over java mail library, that can help you with sending emails and attachments. As you can see in section 'Email using fluent API', you can do the following:
Email email = Email.create()
.from("from#foo.org")
.to("to#bar.com")
.subject("test")
.addText("Hello!")
.addHtml(
"<html><body><h1>Hey!</h1>" +
"<img src='cid:c.png'><h2>Hay!</h2></body></html>")
.embed(attachment().bytes(new File("d:\\c.png")))
.attach(attachment().file("d:\\b.jpg"));
In this example you can see two ways how you can attach your files: embedding them so they appear in HTML content, or common attaching. Of course, you don't have to use fluent interface, its just one option with this library.
I have been trying to get a solution but I am not able to. Here is the whole thing. I wrote the following code
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject);
message.setSentDate(new Date());
MimeBodyPart messagePart = new MimeBodyPart();
messagePart.setContent(messageContent, "text/html");
Multipart multipart = new MimeMultipart("mixed");
multipart.addBodyPart(messagePart);
MimeBodyPart attachmentPart = new MimeBodyPart();
DataSource source = new ByteArrayDataSource(attachment.getBytes(), "text/plain");
attachmentPart.setDataHandler(new DataHandler(source));
attachmentPart.setFileName(attachmentFileName);
multipart.addBodyPart(attachmentPart);
message.setContent(multipart);
try {
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
}
The code is pretty much self explanatory. messagePart is the mail and attachmentPart is the attachment. But messagePart here is not plain text. It is HTML. So the problem is if I run this code mail is sent successfully but the attachment does not come attached to the mail. So my question boils down to this. Is it possible to send html content and attach something to a mail at the same time. I am stuck here. Could anyone help please.
I don't see anything obviously wrong with your code.
How are you determining that the message has no attachment?
You can see exactly what JavaMail would send by adding "message.writeTo(System.out);" just before you call Transport.send.
What version of JavaMail are you using? What mail server are you using? Some mail servers (I'm looking at you, Exchange) will reformat the message to what they think it should be, even if it's different than what you intended.
If you are running on Google App Engine and you add a dummy text part it works great. I have no idea why the dummy text part makes it work, but I was having the exact same problem and adding a dummy text part worked for me too.
You want to add
attachmentPart.setDisposition(Part.ATTACHMENT);
Part.ATTACHMENT means the part should be showed as an attachment.
Part.INLINE means you want to show the attachment as part of the message.
The problem I'm experiencing is when I add the message Body part of the e-mail to the message object before I add the attachments the body of the e-mail doesn't show up, but when I add the message body part after all the attachments it shows up fine.
This is weird, but I have an e-mail I'm trying to send using JavaMail. It has all the regular stuff you need for an e-mail (addresses, etc). The "email" object you'll see below is a Javabean that holds mimeBodyParts for attachments as well as a mimeBodyPart for the message body, subject, etc...
Here's the code that does not work (as described above)
Multipart multipart = new MimeMultipart("alternative");
message.setSubject(email.getSubject());
multipart.addBodyPart(email.getContentBodyPart()); //This is the only line that moves
for (MimeBodyPart mimeBodyPart : email.getBodyParts()) {
multipart.addBodyPart(mimeBodyPart);
}
message.setContent(multipart);
Here's the code that does work:
Multipart multipart = new MimeMultipart("alternative");
message.setSubject(email.getSubject());
for (MimeBodyPart mimeBodyPart : email.getBodyParts()) {
multipart.addBodyPart(mimeBodyPart);
}
multipart.addBodyPart(email.getContentBodyPart()); //This is the only line that moved
message.setContent(multipart);
If you need more info about the email javabean I'll give it to you (or you can find the entire object code here), but I'm guessing I'm just missing something simple. Thanks in advance.
Just to clarify for anyone else reading this: If you use an "alternative" MimeMultipart, all its parts should be alternative versions of the same content. Also according to the relevant RFCs the preferred version of the content should be added last. You do this a lot when creating an HTML email with a plain text fallback. This is why they warn you in the JavaMail docs to read the RFCs.
If you're creating a message with attachments, why are you using a multipart/alternative? You should be using the (default) multipart/mixed.
Did you cut and paste that code without understanding it? :-)
I'm trying to send an email in html format using JavaMail but it always seems to only display as a text email in Outlook.
Here is my code:
try
{
Properties props = System.getProperties();
props.put("mail.smtp.host", mailserver);
props.put("mail.smtp.from", fromEmail);
props.put("mail.smtp.auth", authentication);
props.put("mail.smtp.port", port);
Session session = Session.getDefaultInstance(props, null);
// -- Create a new message --
MimeMessage message = new MimeMessage(session);
// -- Set the FROM and TO fields --
message.setFrom(new InternetAddress(fromEmail, displayName));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
MimeMultipart content = new MimeMultipart();
MimeBodyPart text = new MimeBodyPart();
MimeBodyPart html = new MimeBodyPart();
text.setText(textBody);
text.setHeader("MIME-Version" , "1.0" );
text.setHeader("Content-Type" , text.getContentType() );
html.setContent(htmlBody, "text/html");
html.setHeader("MIME-Version" , "1.0" );
html.setHeader("Content-Type" , html.getContentType() );
content.addBodyPart(text);
content.addBodyPart(html);
message.setContent( content );
message.setHeader("MIME-Version" , "1.0" );
message.setHeader("Content-Type" , content.getContentType() );
message.setHeader("X-Mailer", "My own custom mailer");
// -- Set the subject --
message.setSubject(subject);
// -- Set some other header information --
message.setSentDate(new Date());
// INFO: only SMTP protocol is supported for now...
Transport transport = session.getTransport("smtp");
transport.connect(mailserver, username, password);
message.saveChanges();
// -- Send the message --
transport.sendMessage(message, message.getAllRecipients());
transport.close();
return true;
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw e;
}
Any ideas why the html version of the email won't display in Outlook?
After a lot of investigation, I've been able to make some significant progress.
Firstly, instead of using JavaMail directly, I recommend using the Jakarta Commons Email library. This really simplifies the issue a lot!
The code is now:
HtmlEmail email = new HtmlEmail();
email.setHostName(mailserver);
email.setAuthentication(username, password);
email.setSmtpPort(port);
email.setFrom(fromEmail);
email.addTo(to);
email.setSubject(subject);
email.setTextMsg(textBody);
email.setHtmlMsg(htmlBody);
email.setDebug(true);
email.send();
Talk about simple.
However, there is still an issue. The html version of the email works great in Gmail, Hotmail, etc. But it still won't correctly display in Outlook. It always wants to display the text version and I'm not sure why. I suspect it's a setting in Outlook, but I can't find it...
In addition to removing the html.setHeader("Content-Type", html.getContentType())
call as suggest already, I'd replace the line:
MimeMultipart content = new MimeMultipart();
…with:
MimeMultipart content = new MimeMultiPart("alternative");
…and removing the line:
message.setHeader("Content-Type" , content.getContentType() );
The default MimeMultiPart constructor could be causing problems with a "multipart/mixed" content-type.
When using multipart/alternative, the alternatives are ordered by how faithful they are to the original, with the best rendition last. However, clients usually give users an option to display plain text, even when HTML is present. Are you sure that this option is not enabled in Outlook? How do other user agents, like Thunderbird, or GMail, treat your messages?
Also, ensure that the HTML is well-formed. I'd validate the HTML content with the W3 validation service, and possibly save it into a file and view it with different versions of IE too. Maybe there's a flaw there causing Outlook to fall back to plain text.
html.setContent(htmlBody, "text/html");
html.setHeader("MIME-Version" , "1.0" );
html.setHeader("Content-Type" , html.getContentType() );
setContent and setHeader("Content-Type", String) do the same thing - is it possible that html.getContentType() is returning something other than text/html?
Expanding based on comment and #PhilLho & #erickson's answer (geez, I must type slowly), use:
MimeMultipart content = new MimeMultipart("alternative")
Change this To:
message.setContent(new String(sBuffer.toString().getBytes(), "iso-8859-1"), "text/html; charset=\"iso-8859-1\"");
The content char set need to be set, I don't see why the content itself.
Should rather be:
message.setContent(sBuffer.toString(), "text/html;charset=iso-8859-1");
I used the following code:
mimeBodyPart1.setDataHandler(new DataHandler(new ByteArrayDataSource(messageBody, "text/html; charset=utf-8")));
multiPart.addBodyPart(mimeBodyPart1);
message.setContent(multiPart, "text/html; charset=utf-8");
Now, Outlook displays in html format.
You should look at the source of the received message: is the Content-Type of the message multipart/alternative?
message.setContent(new String(sBuffer.toString().getBytes(), "iso-8859-1"), "text/html; charset=iso-8859-1");
Should solve your problem (removed \" characters).
workaroung solution solved outlook 2003: This message uses a character set that is not supported by the Internet Service. doesn't display correctly.
It could be due to the encoding. Most html pages use iso-8859-1 not cp-1252 try changing
For example, your code is:
message.setContent(sBuffer.toString(), "text/html");
Change this to:
message.setContent(new String(sBuffer.toString().getBytes(), "iso-8859-1"), "text/html; charset=\"iso-8859-1\"");
This throws a new checked exception : java.io.UnsupportedEncodingException so you need to declare it to be thrown or catch it.
iso-8859-1 is supported so, the exception will never be thrown unless something gets corrupted with your rt.jar.
Regards,
Javeed
javeed.mca#gmail.com