JavaMail 更新后的附件文件名字符集问题
Attachment filename charset-issue after JavaMail update
从 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"
如您所见,这几乎是我们想要的,只是现在“Ø”字符被破坏了。其余代码是相同的。我研究了各种设置字符编码的方法,但 none 似乎解决了结果的这个特定部分。
我也用 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);
}
}
为了在 JavaMail 1.6.2 中获得 headers 的旧外观,我需要添加以下两个系统属性:
props.setProperty("mail.mime.encodeparameters", "false");
props.setProperty("mail.mime.allowutf8", "false");
来自the patch notes的mail.mime.allowutf8
的解释:
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);
}
从 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"
如您所见,这几乎是我们想要的,只是现在“Ø”字符被破坏了。其余代码是相同的。我研究了各种设置字符编码的方法,但 none 似乎解决了结果的这个特定部分。
我也用 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);
}
}
为了在 JavaMail 1.6.2 中获得 headers 的旧外观,我需要添加以下两个系统属性:
props.setProperty("mail.mime.encodeparameters", "false");
props.setProperty("mail.mime.allowutf8", "false");
来自the patch notes的mail.mime.allowutf8
的解释:
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);
}