【问题标题】:Attachment filename charset-issue after JavaMail updateJavaMail 更新后的附件文件名字符集问题
【发布时间】:2020-11-16 20:20:11
【问题描述】:

从 JavaMail 1.4.5 更新到 1.6.2 后,我们遇到了附件文件名字符集的问题。这些问题至少部分与encodeparameters 相关,因为我们希望在新版本中将其设置为false,以避免接收者的附件出现问题。这都是在 Windows 环境中执行的。

使用 JavaMail 1.4.5 我们有这样的经历:

Content-Type: application/octet-stream; name="Frammøtebekreftelse.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Frammøtebekreftelse.pdf"

使用 JavaMail 1.6.2 我们有这样的经历:

Content-Type: application/octet-stream; 
    name*=windows-1252''Framm%F8tebekreftelse.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; 
    filename*=windows-1252''Framm%F8tebekreftelse.pdf

我认为这很好,但接收者在name* 格式上存在问题,这导致我们使用encodeparameters=false

使用 JavaMail 1.6.2 和 encodeparameters=false 我们有过这样的经历:

Content-Type: application/octet-stream; name="Frammøtebekreftelse.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Frammøtebekreftelse.pdf"

如您所见,这几乎是我们不想要的,只是现在“Ø”字符被破坏了。其余代码相同。我研究了各种设置字符编码的方法,但似乎没有一种方法可以解决结果的这个特定部分。

我也尝试过使用 JakartaMail 1.6.5 的最后一个版本,结果相同。

我需要设置什么代码或什么 JVM 选项才能做到这一点?

此代码非常普通。下面是一个 MCVE,应该可以证明这个问题:

import java.io.IOException;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class Mcve {
    public static void main(String[] args) throws AddressException, MessagingException, IOException {
        Properties props = System.getProperties();
        props.setProperty("mail.smtp.host", "localhost");
        props.setProperty("mail.mime.encodeparameters", "false");

        Session session = Session.getInstance(props, null);
        MimeMessage message = new MimeMessage(session);

        message.setFrom(new InternetAddress("email@example.com"));
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("email@example.com", false));
        message.setSubject("Frammøtebekreftelse");

        MimeMultipart multipart = new MimeMultipart();

        MimeBodyPart body = new MimeBodyPart();
        body.setContent("Hello world", "text/plain");
        multipart.addBodyPart(body);

        MimeBodyPart attachment = new MimeBodyPart();
        attachment.attachFile("Frammøtebekreftelse.pdf");
        multipart.addBodyPart(attachment);

        message.setContent(multipart);

        Transport.send(message);
    }
}

【问题讨论】:

  • 带笔划的拉丁小写字母 O ølatin-1 编码中是 0xF80xC3,0xB8 字节序列在 utf-8 中(如果在 latin-1 中解释,后者显示为 ø)...
  • @JosefZ 谢谢。因此,如果我没看错的话,MIME 会显示为 latin-1,而输入是 UTF-8。不幸的是,我仍然不确定如何为 MIME 的这个特定部分指定字符编码。它似乎在以前的版本中“正常工作”。
  • 我猜这个mojibake来自不同的发送者和接收者邮件客户端设置(可能是SuperUser的问题?)

标签: java email encoding character-encoding jakarta-mail


【解决方案1】:

为了获得 JavaMail 1.6.2 中标题的旧外观,我需要添加以下两个系统属性:

props.setProperty("mail.mime.encodeparameters", "false");
props.setProperty("mail.mime.allowutf8", "false");

mail.mime.allowutf8 from the patch notes的解释:

mail.mime.allowutf8:

  If set to "true", UTF-8 strings are allowed in message headers,
  e.g., in addresses.  This should only be set if the mail server also
  supports UTF-8.

不幸的是,我并不完全相信这不会弄乱其他一些功能。从我的基本检查来看,LineOutputStream 中至少有以下功能。

1.4.5:

public void writeln(String s) throws IOException {
    byte[] bytes = ASCIIUtility.getBytes(s);
    out.write(bytes);
    out.write(newline);
}

1.6.2:

public void writeln(String s) throws IOException {
    byte[] bytes;
    if (allowutf8)
        bytes = s.getBytes(StandardCharsets.UTF_8);
    else
        bytes = ASCIIUtility.getBytes(s);
    out.write(bytes);
    out.write(newline);
}

【讨论】:

  • 对于那些想知道您是否应该这样做的人:可能不会。我们发现升级的原因是使用 iOS 默认邮件应用程序时出现的“ø”问题。因此,为了提供绝对最大的兼容性,我们最终使用mail.mime.encodeparameters=false 并过滤附件名称以保持在us-ascii 内。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
  • 2019-07-20
相关资源
最近更新 更多