Search code examples
javajakarta-mail

Seems like JavaMail's MimeBodyPart.setFileName inserts a line break in the email message and causes the filename to show up as invalid


We have code that goes out to a person's mailbox and copies emails with attachments to a filesystem.

The code for copying the message and attachment works fine for most files but there's an issue with long filenames.

if (attachment instanceof FileAttachment || attachment.getIsInline()) {
    System.out.println(attachment.getName());
    String FILE_NAME = "C:path\\" + attachment.getName();
    attachment.load(FILE_NAME);

    MimeBodyPart attachmentMime = new MimeBodyPart();
    attachmentMime.setContent(new MimeMultipart(attachment.getContentType()));
    javax.activation.DataSource source = new FileDataSource(FILE_NAME);
    attachmentMime.setDataHandler(new DataHandler(source));
    attachmentMime.setFileName(attachment.getName());
    multipart.addBodyPart(attachmentMime);
} 

For instance, the filename: "Copy of SKI17042 surgery CPT choices for CRLM population.xlsx" shows up in the email attachment with the name "Untitled attachment 00006.dat". When I look at the .eml file that is created, it looks like JavaMail inserts a line break in the middle of the filename which may be causing the issue.

When I open the .eml in a text editor, I see the headers with a line break (notice the line breaks in lines 3/4 and 7/8 that span the filename:

------=_Part_3_840180718.1542390637623
Content-Type: application/octet-stream; 
    name*0="Copy of SKI17042 surgery CPT choices for CRLM
 population.xls"; name*1=x
Content-Transfer-Encoding: base64
Content-Disposition: attachment; 
    filename*0="Copy of SKI17042 surgery CPT choices for CRLM
 population.xls"; filename*1=x

The file content is fine, if you take the file and slap on an .xlsx it opens in Excel with the content as expected.

Does anyone have any info or ideas with how to solve this issue on file attachment name in JavaMail?

Thanks!

EDIT - Solution

    Properties props = System.getProperties();

    props.put("mail.mime.splitlongparameters", false);

    Session session = Session.getInstance(props, null);

    createProjectFolder(folder);

    Message message = new MimeMessage(session);
    message.setFrom(new InternetAddress(objectJSON.getString("from"), objectJSON.getString("fromName")));
    message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(objectJSON.getString("to")));
    message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(objectJSON.getString("cc")));
    message.setSubject(objectJSON.getString("subject"));
    message.setSentDate(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a").parse(objectJSON.getString("date")));

    // create the message part 
    Multipart multipart = new MimeMultipart("mixed");
    MimeBodyPart content = new MimeBodyPart();

    // fill message
    if (objectJSON.getString("body").toLowerCase().contains("html")) {
        content.setContent( objectJSON.getString("body"), "text/html; charset=utf-8" );
    }
    else {
        content.setText(objectJSON.getString("body"), "utf-8");
    }

    multipart.addBodyPart(content);

        if (objectJSON.getInt("hasAttachment") == 1) {

            ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);

            service.setUrl(new URI("https://mail/ews/Exchange.asmx"));

            ExchangeCredentials credentials = new WebCredentials(developerEmail, password);

            service.setCredentials(credentials);

            try {

                EmailMessage messageWithAttachment = EmailMessage.bind(service, new ItemId(emailId));

                    AttachmentCollection attachmentsCol = messageWithAttachment.getAttachments(); 
                    System.out.println("attachments: " + attachmentsCol.getCount());
                    for (int i = 0; i < attachmentsCol.getCount(); i++) { 
                        FileAttachment attachment = (FileAttachment)attachmentsCol.getPropertyAtIndex(i); 

                        if (attachment instanceof FileAttachment || attachment.getIsInline()) {
                            System.out.println(attachment.getName());
                            String FILE_NAME = "C:\\R2D4\\eclipse-workspace\\DataLine\\WebContent\\WEB-INF\\email_attachments\\" + attachment.getName();
                            attachment.load(FILE_NAME);

                            MimeBodyPart attachmentMime = new MimeBodyPart();
                            attachmentMime.setContent(new MimeMultipart(attachment.getContentType()));
                            javax.activation.DataSource source = new FileDataSource(FILE_NAME);
                            attachmentMime.setDataHandler(new DataHandler(source));
                            attachmentMime.setFileName(attachment.getName());
                            multipart.addBodyPart(attachmentMime);

                        } 

                    }

            }
            catch(Exception e) {
                e.printStackTrace();
            }

            service.close();

        }


    // integration
    message.setContent(multipart);
    message.saveChanges();

Solution

  • If the filename is greater than 60 characters long, it will be split across multiple parameters as described in RFC 2231.

    It looks like your code that processes messages doesn't understand how to handle RFC 2231 encoded parameters. Here are possible solutions:

    • you can disable all use of RFC 2231 encoding by setting the property mail.mime.encodeparameters to false.

    • you can disable just the splitting of long parameters by setting the (unfortunately undocumented) property mail.mime.splitlongparameters to false.