Question

I've a problem of downloading arabic attachment files using java mail.

The file name is always ambiguous.

The problem is the Bodypart retrieves the attachment as non-UTF-8 characters.

private void getAttachments(Message temp) throws IOException, MessagingException {
    List<File> attachments = new ArrayList<File>();

    Multipart multipart = (Multipart) temp.getContent();

    System.out.println(multipart.getCount());

    for (int i = 0; i < multipart.getCount(); i++) {
        BodyPart bodyPart = multipart.getBodyPart(i);
        if (!Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
            continue; // dealing with attachments only
        }
        InputStream is = bodyPart.getInputStream();

        // getFilename always have wrong characters set 
        byte [] fileBytes = bodyPart.getFileName().toString().getBytes();

        String filename = new String(fileBytes, "UTF-8");            

        File f = new File("C:\\Attachments\\" + filename);

         System.out.println(f .getName());

         try {
        if (f == null) {
            //filename = File.createTempFile("VSX", ".out").getName();
            return;
        }

        FileOutputStream fos = new FileOutputStream(f );
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        BufferedInputStream bis = new BufferedInputStream(is);

        int aByte;
        while ((aByte = bis.read()) >=0) {
            bos.write(aByte);
        }

        fos.flush();
        bos.flush();
        bos.close();
        bis.close();
        fos.close();
    } // end of try()
    catch (IOException exp) {
        System.out.println("IOException:" + exp);
    }        

        attachments.add(f);
    }
}
Was it helpful?

Solution

The header is encoded according to the mechanism described in RFC 2047 (it's the encoded-word) which says that a section of a header matching =?<encoding>?B?<encoded-bytes>?= is a byte-encoded section. The <encoding> says how to interpret the bytes, and (because it's the B style, not the Q style) the <encoded-bytes> are base-64 encoded.

This is all rather complex. Luckily, you can deal with this easily by using the static javax.mail.internet.MimeUtility.decodeText() method. That means you can switch to this:

String filename = MimeUtility.decodeText(bodyPart.getFileName());

Actually, you're better off combining that with the next line too as well:

File f = new File("C:\\Attachments",
                  MimeUtility.decodeText(bodyPart.getFileName()));

It's better because it avoids more trouble with building filenames than trying to do it all by hand. (It also means that you can factor out that literal pathname into some configuration location.)

OTHER TIPS

This part seems broken to me:

byte[] fileBytes = bodyPart.getFileName().toString().getBytes();
String filename = new String(fileBytes, "UTF-8");            

You're using the default platform encoding to encode the filename (which you'd already got as a string) as bytes, and then decoding them using UTF-8.

What's wrong with:

String filename = bodyPart.getFileName();

? Don't do any more encoding and decoding than you need. Of course, whether your file system can handle such a filename is a different matter, but at least you're not losing data at this point any more...

(Your method of copying the file data is also nastily inefficient and will leave open streams in the case of exceptions. You might want to look at Guava to write easy code which gets this write...)

try:

String decoded = MimeUtility.decodeText(part.getFileName()); 
return Normalizer.normalize(decoded, Normalizer.Form.NFC); 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top