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("mymail@example.com", "Test", "No body", "Привет, Я кусок текста");

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

Message-ID: <00163662e7107ccbe3049c1402fb@google.com>
Date: Sat, 12 Feb 2011 11:21:01 +0000
Subject: Pages
From: mymail@example.com
To: mymail@example.com
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.

Remc4
  • 1,044
  • 2
  • 12
  • 24
Ibolit
  • 9,218
  • 7
  • 52
  • 96

8 Answers8

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);
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Ibolit
  • 9,218
  • 7
  • 52
  • 96
8

Had similar case, following code solved it:

MimeBodyPart att = new MimeBodyPart();
att.setFileName(MimeUtility.encodeText(fileName));
therealprashant
  • 701
  • 15
  • 27
meliniak
  • 762
  • 1
  • 9
  • 16
5

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));
Yuriy N.
  • 4,936
  • 2
  • 38
  • 31
  • 1
    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 Dec 06 '16 at 05:58
  • @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. – Yuriy N. Jul 01 '19 at 16:04
  • it does not help on cases even file name contains international chars such as german umlaut (ae) – benchpresser Dec 02 '20 at 20:19
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.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • The thing is that i don't have a file as such, i need to be able to send a String as an attachment. – Ibolit Feb 10 '11 at 19:25
  • 2
    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. – Buhake Sindi Feb 10 '11 at 22:10
  • 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. – theyuv Nov 08 '17 at 06:19
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");
Iikka
  • 49
  • 2
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);
jankos
  • 896
  • 1
  • 11
  • 16
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: <1439781957.1.1297366787857.JavaMail.dnault@dnault.local>
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--
dnault
  • 8,340
  • 1
  • 34
  • 53
  • I just tried it, and it didn't work, neither did ...= new ByteArrayDataSource(attachment.getBytes("UTF-8") ... – Ibolit Feb 10 '11 at 18:10
  • can you post the raw source of the received email? – dnault Feb 10 '11 at 18:11
  • also, if you don't get an answer here, try the JavaMail forums. Bill Shannon offers an amazing level of support. http://forums.oracle.com/forums/forum.jspa?forumID=975 – dnault Feb 10 '11 at 18:15
  • 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"); – Ibolit Feb 10 '11 at 19:05
  • I wonder if your problem could be related to the compiler's character encoding? http://stackoverflow.com/questions/4927575/java-compiler-platform-file-encoding-problem – dnault Feb 10 '11 at 19:46
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);
            }
        }
Ilya Khudyakov
  • 301
  • 3
  • 15