【问题标题】:JavaMail sending mail attachment from string - encoding UTF-8JavaMail 从字符串发送邮件附件 - 编码 UTF-8
【发布时间】:2011-06-25 00:54:03
【问题描述】:

我的应用程序必须发送一个文本文件,它首先必须将其生成为字符串。文本包含非 ASCII 符号,所以我希望它是 UTF-8。我尝试了很多变体,但我收到的附件只是一些问号。而且,当我发送与消息正文相同的文本时,它可以正常工作。

这是生成带有附件的 MimeBodyPart 的代码行:

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

我还尝试使用不进行任何转换的字符串,只使用字节,现在,如您所见,我正在尝试从字节生成字符串...

我做错了什么? (而且我确实记得在另一个项目中这样做,它有效,但我不再有权访问它的源代码)。

提前谢谢你。 蒂莫菲。

更新

阅读了您的回复,经过一些不成功的实验后,我认为最好发布我的邮件代码。我有Mailer 类,它负责发送邮件,其他类可以调用它的静态sendMessage() 方法来发送消息。所有这些都在 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);
}

在另一个类中调用这个东西的行是:

Mailer.sendMessage("mymail@example.com", "Test", "No body", "Привет, Я кусок текста");

奇怪的是,邮件的原始来源是(省略了看似不相关的标题):

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--

我只是不明白,为什么字符集与我尝试设置的字符集不同,以及它们来自何处。

【问题讨论】:

  • 您在生成的文件中看到正确的字符编码了吗?
  • 没有。在生成的文件中,我只看到问号。

标签: java encoding attachment jakarta-mail


【解决方案1】:

设置内容类型为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);

【讨论】:

    【解决方案2】:

    有类似的情况,下面的代码解决了:

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

    【讨论】:

      【解决方案3】:

      如果问题出在文件名而不是正文中,以下代码在我的(希伯来语)案例中有所帮助:

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

      【讨论】:

      • 在我的情况下,附件名称是日文字符集,我尝试了上面的代码行,但我收到的电子邮件中出现了垃圾字符集(既不是日文也不是 ?????)。你能帮我解决我做错的地方吗?
      • @Akshada 您的附件名称应为 UTF-8。但它可能不是。上面的代码不会将字符串从任何编码转换为 UTF-8。它只是指定其实际编码,以便正确地将其转换为字节并返回字符串。
      • 即使文件名包含德语变音符号 (ae) 等国际字符也无济于事
      【解决方案4】:

      这是我用来发送文件的示例代码(与编码或数据结构无关)。

      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);
      

      其中fileDataSourcejavax.activation.DataSource(文本文件将在此处),并且 fileBodyPart.setDisposition(Part.INLINE);PART.INLINE 表示数据源与邮件正文内联,就像 HTML 电子邮件一样,PART.ATTACHMENT 表示数据源是附件)。

      希望这会有所帮助。

      【讨论】:

      • 问题是我没有这样的文件,我需要能够将字符串作为附件发送。
      • 如果我没记错的话,你可以使用一个接收 InputStream 的数据源。您可以使用具有您的字符串的 InputStream 或将包含您的字符串的临时文件传递给数据源。我必须在早上给你看。
      • 是否有描述附件文件名编码的标题?使用非拉丁文件名时,我的显示为问号。
      【解决方案5】:

      试试这个:

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

      更新:(完整示例)

      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);
          }
      }
      

      输出:

      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--
      

      【讨论】:

      • 我刚试了下,还是不行,...= new ByteArrayDataSource(attachment.getBytes("UTF-8") ...
      • 你能把收到的邮件的原始出处贴出来吗?
      • 另外,如果您在这里没有得到答案,请尝试 JavaMail 论坛。比尔香农提供了惊人的支持水平。 forums.oracle.com/forums/forum.jspa?forumID=975
      • 原始数据源(省略开头):Content-Type:multipart/mixed;边界=.. --002354867bdc4c631e049bf21caf 内容类型:文本/纯文本;字符集=ISO-8859-1;格式=流动; delsp=yes 还没有正文 --002354867bdc4c631e049bf21caf 内容类型:文本/纯文本; charset=US-ASCII; name="2011_1_10_18_54_25_835.txt" 内容配置:附件; filename="2011_1_10_18_54_25_835.txt" Content-Transfer-Encoding: base64 Pz8/Pz8/LCA/ID8/Pz8/ID8/Pz8/Pw== --002354867bdc4c631e049bf21caf-- 这很奇怪,因为我确实将编码设置为 UTF-8 ...setHeader("Content-Type", "text/plain; charset=UTF-8");
      • 不知道您的问题是否与编译器的字符编码有关? stackoverflow.com/questions/4927575/…
      【解决方案6】:

      另一种可能性:

      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");
      

      【讨论】:

        【解决方案7】:

        这行得通:

                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);
        

        【讨论】:

          【解决方案8】:

          我曾经尝试以 url 编码发送文件名。它适用于gmail

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

          完整代码在这里:

          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);
                      }
                  }
          

          【讨论】:

            猜你喜欢
            • 2015-02-10
            • 1970-01-01
            • 2015-04-11
            • 2015-08-24
            • 2018-02-02
            • 2014-03-30
            • 2011-12-14
            • 2011-12-31
            • 2014-06-09
            相关资源
            最近更新 更多