In our system we have mailmessages saved and a function where we can forward these messages.
I know want to be able to add text to the top of the message when we forward it.
This has proven to be surprisingly difficult.
Some of the code.
private void addMessageStartOfMail(MimeMessage mail, String forwardMailBody) throws Exception{
Object content = mail.getContent();
if (content.getClass().isAssignableFrom(MimeMultipart.class)) {
MimeMultipart mimeMultipart = (MimeMultipart) content;
for (int i = 0; i < mimeMultipart.getCount(); i++) {
BodyPart bodyPart = mimeMultipart.getBodyPart(i);
if (bodyPart.getContentType().startsWith("text/plain")) {
String cnt = forwardMailBody;
cnt = MailUtil.toPlainText(cnt);
cnt = cnt + (String)bodyPart.getContent();
bodyPart.setContent(cnt, bodyPart.getContentType());
}
......
This works but unfortunatelly not all mails are text/plain, some are text/html and worse, some are multipart which is a total mess.
The trouble code
}else if(bodyPart.getContentType().startsWith("multipart")) {
Multipart mp = (Multipart) bodyPart.getContent();
int count = mp.getCount();
for (int j = 0; j < count; j++) {
BodyPart bp = mp.getBodyPart(j);
if (bp.getContentType().startsWith("text/html")) {
String cnt = form.getForwardMailBody();
cnt = cnt + (String)bp.getContent();
bp.setContent(cnt, bp.getContentType());
....
For some reason this turns the contenttype from html to plain which makes the original message a mess.
I feel there must be a smarter way to this.
Can I somehow add a simple bodypart to beginning of a Mimemessage or something.
Any advice?
After VGRs answer I made a new attempt.
private void addMessageStartOfMail(MimeMessage mail, String forwardMailBody) throws Exception{
Object content = mail.getContent();
if (content.getClass().isAssignableFrom(MimeMultipart.class)) {
MimeMultipart mimeMultipart = (MimeMultipart) content;
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Test");
mimeMultipart.addBodyPart(messageBodyPart, 0);
}
}
Obviously much cleaner but how do I add the new bodypart. I want it at top of the mail but without overwriting the original mail, which this solution did.
The JavaMail FAQ describes two ways to forward a message.
The simplest way is to create a new message and attach the original message as an attachment.
If instead you want to forward the original message "inline", you need to construct a new body for the message based on the body from the original message. The JavaMail FAQ contains code for finding the main message body. Preserving the original structure of the message with the attachments and so on is much more difficult, especially when you consider all the possible cases of multipart/related, multipart/alternative, etc.
The technique described in the comments above of inserting a new MimeBodyPart into the original message will work in some cases, but it will still be a challenge to find out where exactly to insert it, and the end result may not display as you would like.
Related
I am using Javax mail for reading mail content and will store into database. But when i am reading mail content using java there is question mark found with in the content.
Dear S?ir,
Like this. I have used below code.
Folder folder1 = store.getFolder("INBOX");
if(!folder1.isOpen())
folder1.open(Folder.READ_WRITE);
Message[] message = folder1.getMessages();
Multipart multiPart = (Multipart) message.getContent();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(partCount);
String content = part.getContent().toString();
result = new String (content.getBytes("UTF-8"),"UTF-8");
}
But no luck. How can i remove this question mark?
Hi Below code will might help you. I have used buffer instead of String.
Below is the code.
// Email Message
StringBuffer strMessage = new StringBuffer();
strMessage.append("Thank you for your Request . Your One time password is: "+ otp + ". ");
strMessage.append("\n\n");
strMessage.append("Best Regards");
strMessage.append("\n\n");
strMessage.append("COMPANY NAME");
sendemailinput.setStatus("0");
sendemailinput.setSendType("HTML");
I use javax.mail to download mails from a given mail address in order to get the attachments (I expect images) and save the images on disk automatically (polling the mail address). This works fine except if the mail has been sent from an iPhone. It seems that in these cases the image is embedded in the mail (I can see the image in the web mail window) and cannot be downloaded as an attachment.
How can I extract the image from the mail?
What is the difference between iPhone mails and other mails regarding attachments?
Is the image a special part of the mail content?
In my program log I can see:
- contentType: multipart/mixed; boundary=Apple-Mail-...
- numberOfParts = 2
Java version is 1.7.0_21
javax.mail version is 1.4.7
This is the relevant code (most of it taken from http://www.codejava.net)
if (contentType.contains("multipart")) {
// content may contain attachments
Multipart multiPart = (Multipart) message.getContent();
numberOfParts = multiPart.getCount();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(partCount);
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
// this part is the attachment
String fileName = part.getFileName();
attachFiles += fileName + ", ";
if (fileName.endsWith("jpg") || fileName.endsWith("JPG")
|| fileName.endsWith("jpeg") || fileName.endsWith("JPEG")) {
part.saveFile(saveDirectory + File.separator + fileName);
} else {
// attachment is not an image
}
} else {
// this part may be the message content
messageContent = part.getContent().toString();
}
}
if (attachFiles.length() > 1) {
attachFiles = attachFiles.substring(0, attachFiles.length() - 2);
}
} else if (contentType.contains("text/plain") || contentType.contains("text/html")) {
Object content = message.getContent();
if (content != null) {
messageContent = content.toString();
}
}
Below code can be checked:
Multipart mp = new MimeMultipart("related")
Use the default constructor,which resolves the issue.
The code you have is full of assumptions about the structure of a message. Most likely, one of those assumptions is wrong. Fire up a debugger, add some print statements, or do whatever is necessary to step through your code and compare what you're actually getting with what you expect to get. You can also dump the raw MIME content of the message using the Message.writeTo method, to see what the MIME structure of the message really is.
Probably the first thing to check is whether the image is marked as an ATTACHMENT. Perhaps it's being sent as INLINE instead?
BTW, you never want to use the filename in the message directly; someone could send you all sorts of malicious junk in there.
I have a requirement where I need to process the first line in the email message and, possibly, forward it.
But the problem happens when this message has attachments. And I need to forward them as well. I just can't find a good example of processing email messages with java.mail in a safe way that would cater for multiple message structures. Also, the forwarding example is a problem.
Can anyone point me to a good resource with some code examples?
Thank you
The code of getting the first line of the email message, forwarding I don't have working:
private String getMessgaeFirstLine(Message msg) throws IOException, MessagingException{
String result = null;
Object objRef = msg.getContent();
Multipart mp = (Multipart) objRef;
int count = mp.getCount();
for (int i = 0; i < count; i++)
{
BodyPart bp = mp.getBodyPart( i );
if (bp instanceof MimeBodyPart )
{
MimeBodyPart mbp = (MimeBodyPart) bp;
if ( mbp.isMimeType( "text/plain" )) {
result = (String) mbp.getContent();
result = result.replaceAll("(\\r|\\n)", "");
break;
}
}
}
return result;
}
The simplest way will be to forward the original message as an attachment to the new message. See the JavaMail FAQ.
Is it possible to get only the count of attachments for a mail in Java? I tried using this:
DataHandler handler = message.getDataHandler();
AttachedFileName= handler.getName();
This lists out all the attachments for all mails inbox but not for specific mails.
Is this possible if so how?
Thanks!
This should give you the attachment count,
Multipart multipart = (Multipart) message.getContent();
int attachmentCount = multipart.getCount();
I don't have enough reputation to comment on the accepted solution:
Multipart multipart = (Multipart) message.getContent();
int attachmentCount = multipart.getCount();
But I don't think that it is ideal for the following reasons:
Many email clients [For example: Thunderbird] send all HTML emails as multipart/alternative. They include a HTML part and an alternative plain text part. Historically, it was done to let clients choose the best alternative that they are capable of displaying.
Not everything included as a part is an attachment. For example, many images are not displayed as attachments in email clients because their disposition is set to "inline".
In summary, this solution potentially counts all HTML emails as having attachments and all emails with inline images as having attachments.
Here is an alternative that ignores parts not normally considered attachments:
private int getAttachmentCount(Message message) {
int count = 0;
try {
Object object = mMessage.getContent();
if (object instanceof Multipart) {
Multipart parts = (Multipart) object;
for (int i = 0; i < parts.getCount(); ++i) {
MimeBodyPart part = (MimeBodyPart) parts.getBodyPart(i);
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()))
++count;
}
}
} catch (IOException | MessagingException e) {
e.printStackTrace();
}
return count;
}
I know that this solution gets the body part, but I believe that it is the only accurate way to see if it is an attachment.
I had a similar problem. The accepted answer didn't work for me because multipart may not necessarily be an attachment file. I counted the number of attachments by ignoring the other possible cases in multipart.
int count = 0;
Multipart multipart = (Multipart) message.getContent();
for(int i = multipart.getCount() - 1; i >= 0; i--)
{
BodyPart bodyPart = multipart.getBodyPart(i);
String bodyPartContentType = bodyPart.getContentType();
if(isSimpleType(bodyPartContentType)) continue;
else if(isMultipartType(bodyPartContentType)) continue;
else if(!isTextPlain(bodyPartContentType)) count++;
}
You can check simple type, multipart type, and text using these methods:
private boolean isTextPlain(String contentType)
{
return (contentType.contains("TEXT/PLAIN") || (contentType.contains("TEXT/plain")));
}
private boolean isSimpleType(String contentType)
{
if(contentType.contains("TEXT/HTML") || contentType.contains("text") ||
contentType.contains("TEXT/html")) return true;
return false;
}
private boolean isMultipartType(String contentType)
{
if(contentType.contains("multipart") || contentType.contains("multipart/mixed")) return true;
return false;
}
This worked for me.
Are there any packages available that will efficiently send emails with large attachments (each file is capped at 10mb, but could include multiple files). If not, any suggestions on an appropriate design that wouldn't result in out of memory exceptions causing issues across applications deployed on the same server?
Files are delivered to the application server by ftp. Once transmission is complete, a web service is invoked (metadata for the transaction). Based on business rules, this service may need need to email the files.
My initial thoughts were a putting the request on a message queue (so the service can return immediately), and having a synchronized method process the request (so multiple requests at or around the same time won't blow up the heap).
updating with code
messageBodyPart = new MimeBodyPart();
FileDataSource fileDataSource =new FileDataSource("locationTo.big.file");
messageBodyPart.setDataHandler(new DataHandler(fileDataSource));
messageBodyPart.setFileName("big.file");
multipart.addBodyPart(messageBodyPart);
<rinse..repeat>
message.setContent(multipart);
Transport.send(msg);
If I attach 5 10mb attachments, 50mb won't be eaten up by the heap all at once?
Why not use an Executor, with a thread pool growing/shrinking within reason. Each task submitted is a Runnable or Callable. The Task sends via JavaMail, which DOES not take much memory if you implement your own DataSource implementations for the attachments and/or message body. (I am assuming you have have InputStream acccess to the attachments)
Adding code as sample (note this code was written many years ago, and is pretty bad for many reasons. But it shows the concept)
public static void sendMailAndThrowException(SMTPParams sparams,String subject, DataSource msgTextSource,DataSource[] fids,boolean debug) throws MessagingException {
Session session=getMailSession(sparams);
PrintStream f = null;
if (debug) {
f= getPrintStream();
}
// null is System.out by javamail api
session.setDebug(debug);
session.setDebugOut(f);
try
{
// create a message
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(sparams.getFrom()));
// Recipients are comma delimitted
String to_list[] = sparams.getRecipients().split(",");
InternetAddress[] address = new InternetAddress[to_list.length];
for( int i=0; i< to_list.length; i++)
{
// MJB: remove extraneous spaces, sanity check
String temp = to_list[i].trim();
if (temp.length()>0) {
address[i] = new InternetAddress(to_list[i].trim());
}
}
// Addresses are always TO, never CC or BCC in this library
msg.setRecipients(Message.RecipientType.TO, address);
if ((msg.getAllRecipients() == null) || (msg.getAllRecipients().length==0)) {
throw new MessagingException("No valid recipients");
}
// Set the subject
msg.setSubject(subject,"UTF-8");
// create the Multipart and add its parts to it
Multipart mp = new MimeMultipart();
if (msgTextSource != null) {
// create and fill the first message part
MimeBodyPart mbp1 = new MimeBodyPart();
mbp1.setDataHandler(new DataHandler(msgTextSource));
mp.addBodyPart(mbp1);
}
if( fids != null)
{
for (int i=0;i<fids.length;i++) {
// create the second message part
if (fids[i]==null) continue;
MimeBodyPart mbp2 = new MimeBodyPart();
// attach the file to the message
mbp2.setDataHandler(new DataHandler(fids[i]));
mbp2.setFileName(fids[i].getName());
mp.addBodyPart(mbp2);
}
}
// add the Multipart to the message
msg.setContent(mp);
// set the Date: header
msg.setSentDate(new java.util.Date());
// Connect to SMTP server
smtpSend(session, msg, sparams);
}
catch (MessagingException mex)
{
throw mex;
} finally {
closeDebug(f);
}
}
JavaMail allows easily for sending mails with large attachments if given enough RAM to hold the various pieces.
Any particular reason you cannot use that?