30

My application has to send a textfile, which it first has to generate as a String. The text contains non-ASCII symbols, so i would like it to be UTF-8. I've tried a lot of variants, but all i receive as the attachment is some question marks. And, when i send the same text as the message body, it works all right.

Here is the line of code that generates the MimeBodyPart with the attachment:

String attachment = "Привет";
messageBodyPart.setContent(new String(attachment.getBytes("UTF-8"),
    "UTF-8"),"text/plain; charset=UTF-8");

I also tried using the string without any transformations, using just the bytes, now, as you see, i am trying to generate a string from the bytes...

What am i doing wrong? (And i do remember doing this in another project, which works, but i no longer have the access to its source code).

Thank you in advance. Timofey.

UPDATE

Having read your replies, and after some more unsuccessful experimenting i thought it best to publish the code of my mailing thing. I have the Mailer class, which does the mailing, and other classes can just call its static sendMessage() method to send a message. And it all runs on Google App Engine.

public static void sendMessage(String to, String subject, String msgBody,
            String attachment) throws AddressException, MessagingException {

    Properties props = new Properties();

    Session mailSession = Session.getDefaultInstance(props, null);
    Message msg = new MimeMessage(mailSession);
    String email = "bla-bla-bla"; // userService.getCurrentUser().getEmail();

    msg.setFrom(new InternetAddress(email));
    msg.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

    InternetAddress[] addresses = { new InternetAddress("bla-bla-bla") };

    msg.setReplyTo(addresses);
    msg.setSubject(subject);

    Calendar cal = Calendar.getInstance();

    String fileName = cal.get(Calendar.YEAR) + "_"
            + cal.get(Calendar.MONTH) + "_"
            + cal.get(Calendar.DAY_OF_MONTH) + "_"
            + cal.get(Calendar.HOUR_OF_DAY) + "_"
            + cal.get(Calendar.MINUTE) + "_" + cal.get(Calendar.SECOND)
            + "_" + cal.get(Calendar.MILLISECOND) + ".txt";

    // create the message part
    MimeBodyPart messageBodyPart = new MimeBodyPart();

    // fill message
    // Here we should have the msgBody.
    // Sending attachment contents for debugging only.
    messageBodyPart.setText(attachment + " - 4", "UTF-8", "plain");

    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(messageBodyPart);

    MimeBodyPart att = new MimeBodyPart();
    att.setText(attachment, "UTF-8", "plain");
    att.addHeader("Content-Type", "text/plain; charset=UTF-8"); 

    att.setFileName(fileName);
    multipart.addBodyPart(att);

    // Put parts in message
    msg.setContent(multipart);

    Transport.send(msg);
}

And the line that calls this thing in another class is:

Mailer.sendMessage("[email protected]", "Test", "No body", "Привет, Я кусок текста");

And the raw source of the mail, strangely enough, is (leaving out the seemingly irrelevant headers):

Message-ID: <[email protected]>
Date: Sat, 12 Feb 2011 11:21:01 +0000
Subject: Pages
From: [email protected]
To: [email protected]
Content-Type: multipart/mixed; boundary=00163662e7107ccbd4049c1402fa

--00163662e7107ccbd4049c1402fa
Content-Type: text/plain; charset=KOI8-R; format=flowed; delsp=yes
Content-Transfer-Encoding: base64

8NLJ18XULCDxIMvV08/LINTFy9PUwSAtIDQNCg==
--00163662e7107ccbd4049c1402fa
Content-Type: text/plain; charset=US-ASCII; name="2011_1_12_11_21_1_691.txt"
Content-Disposition: attachment; filename="2011_1_12_11_21_1_691.txt"
Content-Transfer-Encoding: base64

Pz8/Pz8/LCA/ID8/Pz8/ID8/Pz8/Pw==
--00163662e7107ccbd4049c1402fa--

I just don't get it, why the charsets are different from what i am trying to set, and where they come from.

2
  • Do you see correct char encoding in the file you have generated? Commented Feb 10, 2011 at 17:39
  • No. In the generated file i see only the question marks. Commented Feb 10, 2011 at 18:11

8 Answers 8

25

Set the content type to application/octet-stream:

MimeBodyPart attachmentPart = new MimeBodyPart();

try {
  DataSource ds = new ByteArrayDataSource(attachment.getBytes("UTF-8"), "application/octet-stream");
  attachmentPart = new MimeBodyPart();
  attachmentPart.setDataHandler(new DataHandler(ds));
} 
catch (Exception e) {
  Logger.getLogger("Blina").log(Level.SEVERE, Misc.getStackTrace(e));
}

attachmentPart.setFileName(fileName);
multipart.addBodyPart(attachmentPart);

// Put parts in message
msg.setContent(multipart);
Sign up to request clarification or add additional context in comments.

Comments

9

Had similar case, following code solved it:

MimeBodyPart att = new MimeBodyPart();
att.setFileName(MimeUtility.encodeText(fileName));

Comments

6

If problem is in file name, rather than in body, following code helped in my (hebrew) case:

MimeBodyPart attachment = new MimeBodyPart();
attachment.setFileName(MimeUtility.encodeText(filename, "UTF-8", null));

3 Comments

In my case,the attachment name is in Japanese charset and I tried above line of code but i am getting garbage charset in my received email (neither Japanese nor ?????). Can u please help where I am doing wrong ?
@Akshada Your attachment name should be in UTF-8. But it probably isn't. Above code does not converts string from any encoding to UTF-8. It just specifies its actual encoding in order to properly convert it to bytes and back to string.
it does not help on cases even file name contains international chars such as german umlaut (ae)
3

This is a sample code that I use to send files (irrespective on encoding or data structure).

BodyPart fileBodyPart = new MimeBodyPart();
fileBodyPart.setDataHandler(new DataHandler(fileDataSource));
fileBodyPart.setFileName(attachment.getName());
fileBodyPart.setHeader("Content-Type", fileDataSource.getContentType());
fileBodyPart.setHeader("Content-ID", attachment.getName());
fileBodyPart.setDisposition(Part.INLINE);

Where fileDataSource is a javax.activation.DataSource (text file will be in here), and fileBodyPart.setDisposition(Part.INLINE); (PART.INLINE means datasource is inlined with the message body, just like HTML emails, PART.ATTACHMENT means datasource is an attachment).

Hope this helps.

3 Comments

The thing is that i don't have a file as such, i need to be able to send a String as an attachment.
If I remember well, you can use a Data source that takes in an InputStream. You can use an InputStream that has has your String or pass a temp file containing your string to the datasource. I'll have to show you in the morning.
Is there a header that describes the encoding of the file name of the attachment? Mine displays as question marks when using a non-Latin file name.
2

One more possibility:

String attachment = "älytöntä";
MimeBodyPart part = new MimeBodyPart();
part.setText(attachment, "UTF-8");
part.setDisposition("attachment");
part.setFileName("attachment.txt");
part.setHeader("Content-Transfer-Encoding", "base64");
part.setHeader("Content-type", "text/plain; charset=utf-8");

Comments

1

Give this a try:

String attachment = "Привет";
DataSource ds = new ByteArrayDataSource(attachment, "text/plain; charset=UTF-8");
messageBodyPart.setDataHandler(new DataHandler(ds));

UPDATE: (full example)

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

public class Main {
    public static void main(String[] args) throws Exception {
        String attachment = "Привет";
        DataSource ds = new ByteArrayDataSource(attachment, "text/plain; charset=UTF-8");
        MimeBodyPart attachmentPart = new MimeBodyPart();
        attachmentPart.setDataHandler(new DataHandler(ds));

        MimeBodyPart bodyPart = new MimeBodyPart();
        bodyPart.setText("Hello this is some text");

        MimeMultipart mp = new MimeMultipart("mixed");
        mp.addBodyPart(bodyPart);
        mp.addBodyPart(attachmentPart);

        MimeMessage msg = new MimeMessage((Session)null);
        msg.setContent(mp);

        msg.writeTo(System.out);
    }
}

output:

Message-ID: <[email protected]>
MIME-Version: 1.0
Content-Type: multipart/mixed; 
    boundary="----=_Part_0_1579321858.1297366787792"

------=_Part_0_1579321858.1297366787792
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hello this is some text
------=_Part_0_1579321858.1297366787792
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

0J/RgNC40LLQtdGC
------=_Part_0_1579321858.1297366787792--

5 Comments

I just tried it, and it didn't work, neither did ...= new ByteArrayDataSource(attachment.getBytes("UTF-8") ...
can you post the raw source of the received email?
also, if you don't get an answer here, try the JavaMail forums. Bill Shannon offers an amazing level of support. forums.oracle.com/forums/forum.jspa?forumID=975
Raw datasource (omitting the beginning): Content-Type: multipart/mixed; boundary=.. --002354867bdc4c631e049bf21caf Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes No body yet --002354867bdc4c631e049bf21caf Content-Type: text/plain; charset=US-ASCII; name="2011_1_10_18_54_25_835.txt" Content-Disposition: attachment; filename="2011_1_10_18_54_25_835.txt" Content-Transfer-Encoding: base64 Pz8/Pz8/LCA/ID8/Pz8/ID8/Pz8/Pw== --002354867bdc4c631e049bf21caf-- That is strange, for i do set the encoding to UTF-8 ...setHeader("Content-Type", "text/plain; charset=UTF-8");
I wonder if your problem could be related to the compiler's character encoding? stackoverflow.com/questions/4927575/…
1

This works:

        MimeMessage msg = new MimeMessage(session);
        msg.setFrom(sendFrom);
        msg.setSubject(subject, "utf-8");
        msg.setSentDate(new Date());

        // create and fill the first message part
        MimeBodyPart mbp1 = new MimeBodyPart();
        mbp1.setContent(message,"text/plain; charset=UTF-8");
        // mbp1.setContent(message,"text/html; charset=UTF-8"); // with this the attachment will fail

        // create the Multipart and its parts to it
        Multipart mp = new MimeMultipart();
        mp.addBodyPart(mbp1);

        if (attachment!=null){
            // Part two is attachment
            MimeBodyPart mbp2 = new MimeBodyPart();
            mbp2 = new MimeBodyPart();

            DataSource ds = null;
            try {
                ds = new ByteArrayDataSource(attachment.getBytes("UTF-8"), "application/octet-stream");
                } catch (IOException e) {
                e.printStackTrace();
            }
            mbp2.setDataHandler(new DataHandler(ds));
            mbp2.addHeader("Content-Type", "text/plain; charset=\"UTF-8\"");
            mbp2.addHeader("Content-Transfer-Encoding", "base64");

            mbp2.setFileName("attachment.txt");
            mbp2.setDisposition(Part.ATTACHMENT);
            mp.addBodyPart(mbp2);
        }

        // add the Multipart to the message
        msg.setContent(mp);
        msg.saveChanges();

        // send the message
        Transport.send(msg);

Comments

0

I used to try send file name in url encoded. And it works for gmail

messageBodyPart.setFileName(UriUtils.encodePath(attachment.getAttachmentName(), "UTF-8"))

full code here:

if (!CollectionUtils.isEmpty(requestMessage.getAttachments())) {
            MimeBodyPart messageBodyPart;
            String fileName;
            File file;
            for (Attachment attachment : requestMessage.getAttachments()) {
                messageBodyPart = new MimeBodyPart();
                fileName = attachment.getAttachmentName();
                file = new File(fileName);
                FileUtils.writeByteArrayToFile(file, attachment.getAttachment());
                messageBodyPart.setDataHandler(new DataHandler(new FileDataSource(file)));
                messageBodyPart.setFileName(UriUtils.encodePath(attachment.getAttachmentName(), "UTF-8"));
                messageBodyPart.setDisposition(Part.ATTACHMENT);
                multipart.addBodyPart(messageBodyPart);
            }
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.