这篇博客主要是记录一下,发送邮件时,发件人和收件人在数据库中怎样存储,才是最好的。

    先说一下我认为的最佳存储方式:昵称(可省)+空格(可省)+"<"+邮箱号+">"+间隔符+昵称....

    先说一下出现的问题:javax.mail.internet.AddressException: Local address contains control or whitespace in string "发件人@163.com"

    这句话主要的意思就是说:地址异常,本地地址的字符串 包涵控制和空格!

    问题出现的原因:邮件在回复时,前端会直接将发件人回填到收件人位置,不知道为何,从前端传到后台的字符串哪怕只是邮箱号,但是传入javamail的api时,还是会报这个错。但奇怪的是发件时,手动输入收件人邮箱号,却能正常发送。

    问题思考:如果邮件是从QQ或者163等第三方收来的,你会发现,通过网上分享的代码进行解析,通常取到的格式是:昵称(可省)+空格(可省)+"<"+邮箱号+">"+间隔符+昵称....,这样当发件人/收件人被回填到页面,用户发送邮件的时候,控制台就会报javax.mail.internet.AddressException: Local address contains control or whitespace in string 

  解决方案:出现这种问题的解决方案就是,跟前端开发人员约定好将邮箱用尖括号括起来,然后在传给后端,这样,当我们发送邮件的时候,直接取发件人和收件人的邮箱进行操作即可,在数据库中存储时,还是将前台传过来的字符串直接存入数据库中即可,我们只需要把传入javamailAPI的参数做以上变化,保证邮件正常发送即可。

Message message = new MimeMessage(session);
if (to != null && !"".equals(to))//to为前台传过来的收件人字符串集合,多个收件人以“,”间隔
	message.addRecipients(Message.RecipientType.TO, InternetAddress.parse(MimeUtility.encodeText(RecieverUtil.formatAddressWithChinese(to))));
package com.xhl.leads.leadsmail.sendmail.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

/**
 * 收件人util 格式化发件人或者收件人,防止里面带中文字符,而导致无法发送邮件
 * 例如:字符串“xxxx@gmail.com <<xxxx@gmail.com>>,xxx@163.com <xxx@163.com>,白云 
 * <xxx@qq.com>”
 * 得到的效果xxxx@gmail.com,xxx@163.com,xxx@qq.com
 * @author Administrator
 *
 */
@Component
public class RecieverUtil {
	
	/**
	 * 获取收件人/发件人的邮箱--通过正则表达式获取尖括号内的邮箱字符串
     * 例如:字符串“xxxx@gmail.com <<xxxx@gmail.com>>,xxx@163.com <xxx@163.com>”
     * 得到的效果xxxx@gmail.com,xxx@163.com
	 * @param address
	 * @return
	 */
	public static String formatAddressWithChinese(String address) {
		String result = "";
		String regex = "\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+";// 匹配带尖括号的的email
		Pattern p = null;
		Matcher m = null;
		if(address != null && !"".equals(address)) {
			if(address.indexOf(",") != -1) {
				String[] add = address.split(",");
				if(add != null && add.length > 0) {
					for(String a :add) {
						if(a != null && !"".equals(a)) {
							if(a.indexOf("<") != -1 && a.indexOf(">") != -1) {
								a = a.substring(a.lastIndexOf("<") + 1,a.lastIndexOf(">")).trim();//获取最后一个“<”与第一个“>”之间的邮箱,防止出现错误数据,一个邮箱号被多个<>包含  例如:xinceshi@gmail.com <<xinceshi@gmail.com>>
								if(a.contains("@")) {
									result = result + a + ",";
								}
							}else {
								p = Pattern.compile(regex);
								m = p.matcher(a);
								while (m.find()) {
									result = result +  m.group() + ",";
								}
							}
						}
					}
				}
			}else {
				if(address.indexOf("<") != -1 && address.indexOf(">") != -1) {
					address = address.substring(address.lastIndexOf("<") + 1,address.lastIndexOf(">")).trim();
					if(address.contains("@")) {
						result = result + address + ",";
					}
				}else {
					p = Pattern.compile(regex);
					m = p.matcher(address);
					while (m.find()) {
						result = result +  m.group();
					}
				}
			}
		}
		if(result.lastIndexOf(",") != -1) {
			result = result.substring(0, result.lastIndexOf(",")).trim();
		}
		if(result.indexOf(";") != -1) {
			result = result.replaceAll(";", ",");
		}
		return result;
	}
	
    /**
	 * 获取收件人、发件人邮箱---通过javamail的InternetAddress对象来获取
	 * @param address
	 * @return
	 */
	public static String formatAddressWithChineseByInternetAddress(String address) {
		String result = "";
		InternetAddress[] addressArray;
		try {
			addressArray = InternetAddress.parse(address);
			if(addressArray != null && addressArray.length > 0) {
				for(InternetAddress add:addressArray) {
					result = result + add.getAddress().trim() + ",";
				}
			}
			if(result.lastIndexOf(",") != -1)
				result = result.substring(0, result.lastIndexOf(",")).trim();
		} catch (AddressException e) {
			e.printStackTrace();
		}
		return result;
	}
}

有的博客说是IDN的问题,说出现的原因是:Java Mail不支持国际化域名,因此必须使用标准规则来使用IDNA规则来转义它们。用java.net.IDN.toASCII()来把收件人或者发件人进行转义,即:to = IDN.toASCII(to);但是我试了一下,不适用我的程序。

 

    我用自己的想法避开了出现这种问题的情况,也算是一种解决方案吧~~