`

javax.mail.Message发送Email,带附件,异步

阅读更多
package 

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class TestMailSender {
	private static final Logger log = LoggerFactory.getLogger(MailSender.class);
	
	/* 邮箱配置详情 */
	private static final String MAIL_SMTP_AUTH = "true";
	private static final String MAIL_HOST = "";
	private static final String MAIL_TRANSPORT_PROTOCOL = "smtp";
	private static final String MAIL_SMTP_PORT = "25";
	private static final String MAIL_AUTH_NAME = "";
	private static final String MAIL_AUTH_PASSWORD = "";
	private static final String MAIL_DISPLAY_SENDNAME = "发件人";
	private static final String MAIL_DISPLAY_SENDMAIL = "";
	private static final String MAIL_SEND_CHARSET = "UTF-8";
	private static final boolean MAIL_IS_DEBUG = true;
	
	/* 邮箱逻辑配置 */
	private static final int MAIL_FAILED_RESEND_TIMES = 3; 								// 同步、异步发送邮件失败,尝试发送次数
	private static final long MAIL_FAILED_ASYN_RESEND_WAITING_MILLISECONDS = 10000; 	// 异步多线程发送邮件失败,重试间隔时间
	private static final long MAIL_FAILED_SYNC_RESEND_WAITING_MILLISECONDS = 3000;  	// 同步发送邮件失败,线程等待时间
	public static final long MAIL_ASYN_SEND_SPACING_MILLISECONDS = 2000;
	public static final long MAIL_SYNC_SEND_SPACING_MILLISECONDS = 1000;
	
	private static final Message message = initMessage();
	
	// 初始化邮箱配置
	private static final Message initMessage() {
		// 基本配置
		Properties props = new Properties();
		props.setProperty("mail.smtp.auth", MAIL_SMTP_AUTH);
		props.setProperty("mail.host", MAIL_HOST);
		props.setProperty("mail.transport.protocol", MAIL_TRANSPORT_PROTOCOL);
		props.setProperty("mail.smtp.port", MAIL_SMTP_PORT);

		Session session = Session.getInstance(props, new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(MAIL_AUTH_NAME,
						MAIL_AUTH_PASSWORD);
			}
		});

		session.setDebug(MAIL_IS_DEBUG);
		Message message = new MimeMessage(session);

		try {
			message.setFrom(new InternetAddress(MimeUtility
					.encodeText(MAIL_DISPLAY_SENDNAME)
					+ "<"
					+ MAIL_DISPLAY_SENDMAIL + ">"));
		} catch (AddressException e) {
			log.error("初始化邮箱配置失败", e);
			throw new RuntimeException(e.getMessage());
		} catch (UnsupportedEncodingException e) {
			log.error("初始化邮箱配置失败", e);
			throw new RuntimeException(e.getMessage());
		} catch (MessagingException e) {
			log.error("初始化邮箱配置失败", e);
			throw new RuntimeException(e.getMessage());
		}
		return message;
	}
	
	/**
	 * 异步根据主题和内容发送邮件
	 * 
	 * @param subject 邮件主题
	 * @param content 邮件内容
	 * @param beSentMails 接收邮件的邮箱地址,不合法的邮箱会自动过滤,如果没有合法邮箱不会发送任何邮件
	 */
	public static void asynMail(String subject, String content, String... beSentMails) {
		Thread thread = new MailSenderByContentDetailThread(subject, content, beSentMails);
		thread.start();
	}
	
	/**
	 * 异步根据主题和内容发送邮件(带附件)
	 * 
	 * @param subject 邮件主题
	 * @param content 邮件内容
	 * @param attachmentName 附件文件名
	 * @param attachmentFile 附件地址
	 * @param beSentMails 接收邮件的邮箱地址,不合法的邮箱会自动过滤,如果没有合法邮箱不会发送任何邮件
	 */
	public static void asynMultiMail(String subject, String content, String attachmentName, String attachmentFile, String... beSentMails) {
		Thread thread = new MailSenderByContentDetailThread(subject, content, attachmentName, attachmentFile,beSentMails);
		thread.start();
	}
	
	/**
	 * 内部包装,根据主题和内容发送邮件
	 * 
	 * @param subject 邮件主题
	 * @param content 邮件内容
	 * @param beSentMails 接收邮件的邮箱地址,不合法的邮箱会自动过滤,如果没有合法邮箱不会发送任何邮件
	 */
	private static final synchronized void sendMail(String subject, String content, String... beSentMails) {
		// 过滤不合法邮箱
		beSentMails = validBeSentMails(beSentMails);

		// 检验过滤结果
		if (ArrayUtils.isEmpty(beSentMails)) {
			return;
		}
		
		try {
			message.setSubject(subject);
			message.setContent(content,"text/html;charset=" + MAIL_SEND_CHARSET );
			
			Address[] addresses = new Address[beSentMails.length];
			for (int i = 0; i < beSentMails.length; i++) {
				addresses[i] = new InternetAddress(beSentMails[i]);
			}
			message.setRecipients(Message.RecipientType.TO, addresses);
			Transport.send(message);
		} catch (Exception e) {
			log.error("根据主题和内容发送邮失败", e);
			throw new RuntimeException("resend" + e.getMessage());
		}
		
	}
	
	/**
	 * 内部包装,根据主题和内容发送邮件(带附件)
	 * 
	 * @param subject 邮件主题
	 * @param content 邮件内容
	 * @param attachmentName 附件文件名
	 * @param attachmentFile 附件地址
	 * @param beSentMails 接收邮件的邮箱地址,不合法的邮箱会自动过滤,如果没有合法邮箱不会发送任何邮件
	 */
	private static final synchronized void sendMultiMail(String subject, String content, String attachmentName, String attachmentFile, String... beSentMails) {
		// 过滤不合法邮箱
		beSentMails = validBeSentMails(beSentMails);

		// 检验过滤结果
		if (ArrayUtils.isEmpty(beSentMails)) {
			return;
		}
		
		try {
			//邮件标题
			message.setSubject(subject);
			//message.setContent(content,"text/html;charset=" + MAIL_SEND_CHARSET );
			
			Multipart multipart = new MimeMultipart();
			
			//设置邮件的文本内容
	        BodyPart contentPart = new MimeBodyPart();
	        contentPart.setText(content);
	        multipart.addBodyPart(contentPart);
	        
	        //添加附件
	        BodyPart messageBodyPart= new MimeBodyPart();
	        DataSource source = new FileDataSource(attachmentFile);
	        //添加附件的内容
	        messageBodyPart.setDataHandler(new DataHandler(source));
	        //添加附件的标题
	        messageBodyPart.setFileName(attachmentName);
	        
	        multipart.addBodyPart(messageBodyPart);
	        
	        //将multipart对象放到message中
            message.setContent(multipart);
            //保存邮件
            message.saveChanges();
			
			Address[] addresses = new Address[beSentMails.length];
			for (int i = 0; i < beSentMails.length; i++) {
				addresses[i] = new InternetAddress(beSentMails[i]);
			}
			message.setRecipients(Message.RecipientType.TO, addresses);
			Transport.send(message);
		} catch (Exception e) {
			log.error("根据主题和内容发送邮失败", e);
			throw new RuntimeException("resend" + e.getMessage());
		}
		
	}
	
	// 返回所有合法的邮箱,都不合法则返回空
	private static String[] validBeSentMails(String... beSentMails) {
		// 没有任何接收邮箱
		if (ArrayUtils.isEmpty(beSentMails)) {
			return null;
		}

		// 验证邮箱格式合法性
		Pattern pattern = Pattern.compile("^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$");
		List<String> finalBeSentMails = new ArrayList<String>();
		for (String tmp : beSentMails) {
			if (StringUtils.isEmpty(tmp)) {
				continue;
			}

			Matcher matcher = pattern.matcher(tmp);
			if (matcher.matches()) {
				finalBeSentMails.add(tmp);
			}
		}

		// 只给合法的地址发送邮件
		if (finalBeSentMails.size() != beSentMails.length) {
			if (finalBeSentMails.size() == 0) {
				return null;
			}
			return finalBeSentMails.toArray(new String[finalBeSentMails.size()]);
		}
		
		// 所有邮箱均合法
		return beSentMails;
	}
	
	// 根据详情发送邮件线程类
	static final class MailSenderByContentDetailThread extends Thread {
		private String subject;
		private String content;
		private String[] beSentMails;
		private String attachmentName;//附件文件名
		private String attachmentFile;//附件文件位置
		
		MailSenderByContentDetailThread(String subject, String content, String[] beSentMails) {
			this.subject = subject;
			this.content = content;
			this.beSentMails = beSentMails;
			this.attachmentName = null;
			this.attachmentFile = null;
		}
		
		MailSenderByContentDetailThread(String subject, String content, String attachmentName, String attachmentFile, String[] beSentMails) {
			this.subject = subject;
			this.content = content;
			this.beSentMails = beSentMails;
			this.attachmentName = attachmentName;
			this.attachmentFile = attachmentFile;
		}
		
		@Override
		public void run() {
			int sendTimes = 0;
			int i = 0;
			// 发送次数在允许尝试范围内
			do {
				try {
					// 发送邮件
					for (; i < beSentMails.length; i++) {
						if(StringUtils.isNotBlank(attachmentName) && StringUtils.isNotBlank(attachmentFile)){
							TestMailSender.sendMultiMail(subject, content, attachmentName, attachmentFile, beSentMails[i]);
						}else{
							TestMailSender.sendMail(subject, content, beSentMails[i]);
						}
						if (i < beSentMails.length - 1) {
							Thread.sleep(MAIL_ASYN_SEND_SPACING_MILLISECONDS);
						}
					}
					break;
				} catch(Exception e) {
					// 不是邮件发送的异常,直接输出错误信息并跳出
					if (!e.getMessage().startsWith("resend")) {
						log.error("邮件发送失败", e);
						break;
					}
					
					// 发送次数已到达允许尝试范围,记录错误信息
					if (sendTimes == MAIL_FAILED_RESEND_TIMES) {
						log.error("邮件发送失败,错误原因:{}" , e.getMessage().substring(6, e.getMessage().length() - 1));
						log.error("发送主题为:{}" ,subject);
						log.error("发送内容为:{}" , content);
						log.error("接收邮箱有:{}" , Arrays.toString(beSentMails));
						log.error("为<{}>发送邮件时出错,后续邮件均未发送。",beSentMails[i]);
						break;
					}
					
					
					// 线程休眠后重试
					try {
						Thread.sleep(MAIL_FAILED_ASYN_RESEND_WAITING_MILLISECONDS);
					} catch (InterruptedException e1) {
						log.error("线程休眠后重试失败", e1);
					}
				}
			} while (sendTimes++ < MAIL_FAILED_RESEND_TIMES);
		}
	}
	
	
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics