这篇博客主要是记录一下,发送邮件时,发件人和收件人在数据库中怎样存储,才是最好的。
先说一下我认为的最佳存储方式:昵称(可省)+空格(可省)+"<"+邮箱号+">"+间隔符+昵称....
先说一下出现的问题: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);但是我试了一下,不适用我的程序。
我用自己的想法避开了出现这种问题的情况,也算是一种解决方案吧~~