Java发送邮件Excel附件名称变为.dat文件

在使用JavaMail发送包含Excel附件的邮件时,附件名称被错误地显示为ATT_*****.dat。通过研究MultiPartEmail的attach方法和MimeBodyPart的setFileName方法,发现是由于ParameterList类的splitLongParameters环境变量导致的。通过在SpringBoot启动类中设置该变量为false,避免文件名切分,成功解决了附件名称显示异常的问题。

Java编写发送邮件,并且添加Excel文件作为附件,邮件可以发送成功,但是附件名称似乎有些问题,总是变成ATT_*****.dat文件,在网上找了许多资料,参考了一些大神的方法,终于解决了该问题。

这用到的邮件类是MultiPartEmail,进入该类的attach方法:

public MultiPartEmail attach(
        final DataSource ds,
        String name,
        final String description,
        final String disposition)
        throws EmailException
    {
        if (EmailUtils.isEmpty(name))
        {
            name = ds.getName();
        }
        final BodyPart bodyPart = createBodyPart();
        try
        {
            bodyPart.setDisposition(disposition);
            bodyPart.setFileName(MimeUtility.encodeText(name));
            bodyPart.setDescription(description);
            bodyPart.setDataHandler(new DataHandler(ds));

            getContainer().addBodyPart(bodyPart);
        }
        catch (final UnsupportedEncodingException uee)
        {
            // in case the filename could not be encoded
            throw new EmailException(uee);
        }
        catch (final MessagingException me)
        {
            throw new EmailException(me);
        }
        setBoolHasAttachments(true);

        return this;
    }

接下来看看setFileName方法,这里进入的是Part接口的一个实现类MimeBodyPart中的setFileName方法

static void setFileName(MimePart part, String name) 
		throws MessagingException {
	if (encodeFileName && name != null) {
	    try {
		name = MimeUtility.encodeText(name);
	    } catch (UnsupportedEncodingException ex) {
		throw new MessagingException("Can't encode filename", ex);
	    }
	}

	// Set the Content-Disposition "filename" parameter
	String s = part.getHeader("Content-Disposition", null);
	ContentDisposition cd = 
		new ContentDisposition(s == null ? Part.ATTACHMENT : s);
	// ensure that the filename is encoded if necessary
	String charset = MimeUtility.getDefaultMIMECharset();
	ParameterList p = cd.getParameterList();
	if (p == null) {
	    p = new ParameterList();
	    cd.setParameterList(p);
	}
	if (encodeFileName)
	    p.setLiteral("filename", name);
	else
	    p.set("filename", name, charset);
	part.setHeader("Content-Disposition", cd.toString());

	/*
	 * Also attempt to set the Content-Type "name" parameter,
	 * to satisfy ancient MUAs.  XXX - This is not RFC compliant.
	 */
	if (setContentTypeFileName) {
	    s = part.getHeader("Content-Type", null);
	    s = MimeUtil.cleanContentType(part, s);
	    if (s != null) {
		try {
		    ContentType cType = new ContentType(s);
		    // ensure that the filename is encoded if necessary
		    p = cType.getParameterList();
		    if (p == null) {
			p = new ParameterList();
			cType.setParameterList(p);
		    }
		    if (encodeFileName)
			p.setLiteral("name", name);
		    else
			p.set("name", name, charset);
		    part.setHeader("Content-Type", cType.toString());
		} catch (ParseException pex) { }	// ignore it
	    }
	}
    }

方法内部使用了ParameterList类,这个类的toString方法中有这样一段

if (value.length() > 60 &&
				splitLongParameters && encodeParameters) {
		    int seg = 0;
		    name += "*";
		    while (value.length() > 60) {
			sb.addNV(name + seg, quote(value.substring(0, 60)));
			value = value.substring(60);
			seg++;
		    }
		    if (value.length() > 0)
			sb.addNV(name + seg, quote(value));
		} else {
		    sb.addNV(name, quote(value));
		}

如果长度超过60,并后面两个值为true,方法内部会将值进行切分。查看该类代码,不难发现这两个值是环境变量,如果不设定则默认值未true,而文件名经过64位编码后很容易超长,因此最终的文件名被切分。

splitLongParameters这个环境变量可以看出是用来切割超长参数的,最终的解决的办法就是在程序启动时将改变量值设置为false,这样文件名就不会被切分。在SpringBoot的启动类或者程序的启动监听类中添加如下代码,再尝试发送邮件中的附件名就正常了。

System.setProperty("mail.mime.splitlongparameters","false");

本文借鉴https://blog.youkuaiyun.com/wty19/article/details/50607411,感谢原博主!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值