import java.io.UnsupportedEncodingException;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import java.security.Security;
import job.tot.bean.MailBean;
import job.tot.exception.BadInputException;
import job.tot.filter.DisableHtmlTagFilter;
import job.tot.global.Sysconfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public final class MailUtils {
public static final int MAX_MESSAGES_PER_TRANSPORT = 100;
public static final boolean useSSL = true;
private static Log log = LogFactory.getLog(MailUtils.class);
private MailUtils() {// prevent instantiation
}
//private static MailOptions mailOption = new MailOptions();
/**
* Get the user name part of an email. Ex: input: test@yahoo.com => output:
* test
*
* @param email String the email
* @return String the user name part of an email
*/
public static String getEmailUsername(String email) {
if (email == null) {
return "";
}
int atIndex = email.indexOf('@');
if (atIndex == -1) {
return "";
}
return email.substring(0, atIndex);
}
/**
* Get the domain part of an email. Ex: input: test@yahoo.com => output:
* yahoo.com
*
* @param email String the email
* @return String the user name part of an email
*/
public static String getEmailDomain(String email) {
if (email == null) {
return "";
}
int atIndex = email.indexOf('@');
if (atIndex == -1) {
return "";
}
return email.substring(atIndex + 1);
}
/**
* Check if an email is good and safe or not. This method should be use for
* all email input from user
*
* @param input String
* @throws BadInputException if email is not good
*/
public static void checkGoodEmail(String input) throws BadInputException {
if (input == null) {
throw new BadInputException("Sorry, null string is not a good email.");//@todo : localize me
}
int atIndex = input.indexOf('@');
int dotIndex = input.lastIndexOf('.');
if ((atIndex == -1) || (dotIndex == -1) || (atIndex >= dotIndex)) {
//@todo : localize me
throw new BadInputException("Error: '" + DisableHtmlTagFilter.filter(input) + "' is not a valid email value. Please try again.");
}
// now check for content of the string
int length = input.length();
char c = 0;
for (int i = 0; i < length; i++) {
c = input.charAt(i);
if ((c >= 'a') && (c <= 'z')) {
// lower char
} else if ((c >= 'A') && (c <= 'Z')) {
// upper char
} else if ((c >= '0') && (c <= '9')/* && (i != 0)*/) {
// as of 31 Jan 2004, i relax the email checking
// so that the email can start with an numeric char
// hopefully it does not introduce a security bug
// because this value will be inserted into sql script
// numeric char
} else if (((c == '_') || (c == '-') || (c == '.') || (c == '@')) && (i != 0)) {
// _ char
} else {
// not good char, throw an BadInputException
//@todo : localize me
throw new BadInputException(input + " is not a valid email. Reason: character '" + c + "' is not accepted in an email.");
}
}// for
// last check
try {
new javax.mail.internet.InternetAddress(input);
} catch (Exception ex) {
log.error("Error when running checkGoodEmail", ex);
throw new BadInputException("Assertion: dont want to occur in Util.checkGoodEmail");
}
}
/**
* 使用加密的方式,利用465端口进行传输邮件,开启ssl
*
* @param to 为收件人邮箱
* @param message 发送的消息
* @param bcc 暗抄送
* @param fileList发送的附件
public static int sendEmailSSL(String from, String to, String cc, String bcc, String subject, String message, String fileList[]) {
int ifcg=0;
try {
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
//设置邮件会话参数
Properties props = new Properties();
int ports = Sysconfig.getMailServerPort();
//邮箱的发送服务器地址
props.setProperty("mail.smtp.host", Sysconfig.getMailServer());
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
//邮箱发送服务器端口,这里设置为465端口
props.setProperty("mail.smtp.port", String.valueOf(ports));
props.setProperty("mail.smtp.socketFactory.port", String.valueOf(ports));
props.put("mail.smtp.auth", "true");
final String username = Sysconfig.getMailUserName();
final String password = Sysconfig.getMailPassword();
//获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm
Session session = Session.getDefaultInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
//通过会话,得到一个邮件,用于发送
Message msg = new MimeMessage(session);
//设置发件人
msg.setFrom(new InternetAddress(from));
// msg.setSubject(MimeUtility.encodeText(subject, "UTF-8", "B"));
// msg.setContent(message, "text/html;charset=UTF-8");
//设置收件人,to为收件人,cc为抄送,bcc为密送
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc, false));
msg.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(bcc, false));
msg.setSubject(subject);
//设置邮件消息
//msg.setText(message);
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(message);
messageBodyPart.setHeader("Content-Type", "text/html;charset=GBK");
//messageBodyPart.setHeader("Content-Transfer-Encoding", "quoted-printable");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// 2.保存多个附件
if (fileList != null) {
addTach(fileList, multipart);
}
multipart.setSubType("mixed");
msg.setContent(multipart);
msg.saveChanges();
//设置发送的日期
msg.setSentDate(new Date());
//调用Transport的send方法去发送邮件
// Transport.send(msg);
Transport.send(msg, msg.getAllRecipients());
} catch (Exception e) {
ifcg=1;
e.printStackTrace();
}
return ifcg;
}
// 添加多个附件
public static void addTach(String fileList[], Multipart multipart)
throws MessagingException, UnsupportedEncodingException {
for (int index = 0; index < fileList.length; index++) {
MimeBodyPart mailArchieve = new MimeBodyPart();
FileDataSource fds = new FileDataSource(fileList[index]);
mailArchieve.setDataHandler(new DataHandler(fds));
mailArchieve.setFileName(MimeUtility.encodeText(fds.getName(),
"GBK", "B"));
multipart.addBodyPart(mailArchieve);
}
}
/**
* NOTE: param to, cc, bcc cannot be all empty. At least one must have a
* valid value
*
* @param from : must be a valid email. However, if this param is null, then
* the default mail in config file will be use
* @param to : can be null
* @param cc : can be null
* @param bcc: can be null
* @param subject
* @param message
* @throws MessagingException
* @throws BadInputException
*/
public static void sendMail(String from, String to, String cc, String bcc, String subject, String message)
throws MessagingException, BadInputException, UnsupportedEncodingException {
MailBean mailItem = new MailBean();
mailItem.setFrom(from);
mailItem.setTo(to);
mailItem.setCc(cc);
mailItem.setBcc(bcc);
mailItem.setSubject(subject);
mailItem.setMessage(message);
sendMail(mailItem);
}
public static void sendMail(MailBean mailItem)
throws MessagingException, BadInputException, UnsupportedEncodingException {
ArrayList mailList = new ArrayList(1);
mailList.add(mailItem);
try {
sendMail(mailList);
} catch (MessagingException mex) {
log.error("MessagingException has occured.", mex);
log.debug("MessagingException has occured. Detail info:");
log.debug("from = " + mailItem.getFrom());
log.debug("to = " + mailItem.getTo());
log.debug("cc = " + mailItem.getCc());
log.debug("bcc = " + mailItem.getBcc());
log.debug("subject = " + mailItem.getSubject());
log.debug("message = " + mailItem.getMessage());
throw mex;// this may look redundant, but it is not :-)
}
}
public static void sendMail(Collection mailStructCollection)
throws MessagingException, BadInputException, UnsupportedEncodingException {
Session session = null;
Transport transport = null;
int totalEmails = mailStructCollection.size();
int count = 0;
int sendFailedExceptionCount = 0;
String server = "";
String userName = "";
String password = "";
int port = 25;
boolean useMailsource = Sysconfig.isUseMailSource();
try {
for (Iterator iter = mailStructCollection.iterator(); iter.hasNext();) {
count++;
if ((transport == null) || (session == null)) {
if (useMailsource) {
try {
InitialContext ic = new InitialContext();
// mailSourceName = "java:comp/env/mail/mailSession";
String mailSourceName = Sysconfig.getMailSourceName();
log.debug("MailUtil : use mailsource = " + mailSourceName);
session = (Session) ic.lookup("java:comp/env/" + mailSourceName);
transport = session.getTransport("smtp");
} catch (NamingException e) {
log.error("Cannot get Mail session", e);
throw new MessagingException("Cannot get the mail session from JNDI. Send mail failed.");
}
} else {// does not use datasourse
Properties props = new Properties();
server = Sysconfig.getMailServer();
port = Sysconfig.getMailServerPort();
userName = Sysconfig.getMailUserName();
password = Sysconfig.getMailPassword();
props.put("mail.smtp.host", server);
props.put("mail.smtp.port", String.valueOf(port));
if ((userName != null) && (userName.length() > 0)) {
props.put("mail.smtp.auth", "true");
}
//props.put("mail.debug", "true");
session = Session.getDefaultInstance(props, null);
transport = session.getTransport("smtp");
}// end of does not use datasource
if ((userName != null) && (userName.length() > 0)) {
transport.connect(server, userName, password);
} else {
transport.connect();
}
}
MailBean mailItem = (MailBean) iter.next();
String from = mailItem.getFrom();
String to = mailItem.getTo();
String cc = mailItem.getCc();
String bcc = mailItem.getBcc();
String subject = mailItem.getSubject();
String message = mailItem.getMessage();
//if (from == null) from = mailOption.defaultMailFrom;
if (from == null) {
from = Sysconfig.getDefaultMailFrom();
}
try {
// this will also check for email error
checkGoodEmail(from);
InternetAddress fromAddress = new InternetAddress(from);
InternetAddress[] toAddress = getInternetAddressEmails(to);
InternetAddress[] ccAddress = getInternetAddressEmails(cc);
InternetAddress[] bccAddress = getInternetAddressEmails(bcc);
if ((toAddress == null) && (ccAddress == null) && (bccAddress == null)) {
//@todo : localize me
throw new BadInputException("Cannot send mail since all To, Cc, Bcc addresses are empty.");
}
// create a message
MimeMessage msg = new MimeMessage(session);
msg.setSentDate(new Date());
msg.setFrom(fromAddress);
if (toAddress != null) {
msg.setRecipients(Message.RecipientType.TO, toAddress);
}
if (ccAddress != null) {
msg.setRecipients(Message.RecipientType.CC, ccAddress);
}
if (bccAddress != null) {
msg.setRecipients(Message.RecipientType.BCC, bccAddress);
}
//This code is use to display unicode in Subject
//msg.setSubject(MimeUtility.encodeText(subject, "iso-8859-1", "Q"));
//msg.setText(message);
//String content = new String(message.getBytes(""), "UTF-8");
msg.setSubject(subject, "UTF-8");
//msg.setText(message, "UTF-8");
/*
//Below code is use for unicode*/
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(message);
messageBodyPart.setHeader("Content-Type", "text/html;charset=gbk");
//messageBodyPart.setHeader("Content-Transfer-Encoding", "quoted-printable");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
msg.setContent(multipart);
msg.saveChanges();
transport.sendMessage(msg, msg.getAllRecipients());
// now check if sent 100 emails, then close connection (transport)
if ((count % MAX_MESSAGES_PER_TRANSPORT) == 0) {
try {
if (transport != null) {
transport.close();
}
} catch (MessagingException ex) {
}
transport = null;
session = null;
}
} catch (SendFailedException ex) {
sendFailedExceptionCount++;
log.error("SendFailedException has occured.", ex);
log.warn("SendFailedException has occured. Detail info:");
log.warn("from = " + from);
log.warn("to = " + to);
log.warn("cc = " + cc);
log.warn("bcc = " + bcc);
log.warn("subject = " + subject);
log.info("message = " + message);
if ((totalEmails != 1) && (sendFailedExceptionCount > 10)) {
throw ex;// this may look redundant, but it is not :-)
}
} catch (MessagingException mex) {
log.error("MessagingException has occured.", mex);
log.warn("MessagingException has occured. Detail info:");
log.warn("from = " + from);
log.warn("to = " + to);
log.warn("cc = " + cc);
log.warn("bcc = " + bcc);
log.warn("subject = " + subject);
log.info("message = " + message);
throw mex;// this may look redundant, but it is not :-)
}
}//for
} finally {
try {
if (transport != null) {
transport.close();
}
} catch (MessagingException ex) {
}
if (totalEmails != 1) {
log.info("sendMail: totalEmails = " + totalEmails + " sent count = " + count);
}
}
}
/**
* This method trim the email variable, so if it contains only spaces, then
* it will be empty string, then we have 0 token :-) The returned value is
* never null
*/
public static String[] getEmails(String email) throws BadInputException {
if (email == null) {
email = "";
}
email = email.trim();// very important
email = email.replace(',', ';');// replace all occurrence of ',' to ';'
StringTokenizer t = new StringTokenizer(email, ";");
String[] ret = new String[t.countTokens()];
int index = 0;
while (t.hasMoreTokens()) {
String mail = t.nextToken().trim();
checkGoodEmail(mail);
ret[index] = mail;
//log.debug(ret[index]);
index++;
}
return ret;
}
public static String[] getEmails(String to, String cc, String bcc) throws BadInputException {
String[] toMail = getEmails(to);
String[] ccMail = getEmails(cc);
String[] bccMail = getEmails(bcc);
String[] ret = new String[toMail.length + ccMail.length + bccMail.length];
int index = 0;
for (int i = 0; i < toMail.length; i++) {
ret[index] = toMail[i];
index++;
}
for (int i = 0; i < ccMail.length; i++) {
ret[index] = ccMail[i];
index++;
}
for (int i = 0; i < bccMail.length; i++) {
ret[index] = bccMail[i];
index++;
}
return ret;
}
/**
* This method will return null if there is not any email
*
* @param email
* @return
* @throws BadInputException
* @throws AddressException
*/
private static InternetAddress[] getInternetAddressEmails(String email)
throws BadInputException, AddressException {
String[] mails = getEmails(email);
if (mails.length == 0) {
return null;// must return null, not empty array
}
//log.debug("to = " + mails);
InternetAddress[] address = new InternetAddress[mails.length];
for (int i = 0; i < mails.length; i++) {
address[i] = new InternetAddress(mails[i]);
//log.debug("to each element = " + mails[i]);
}
return address;
}
}