javax.mail.Message发送Email,带附件,异步
程序员文章站
2022-04-14 17:52:30
...
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); } } }