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

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位编码后很容易超长,因此最终的文件名被切分。

Java发送邮件Excel附件名称变为.dat文件_第1张图片

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

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

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

你可能感兴趣的:(源码剖析)