本文主要是讲述JavaMail 和 消息队列的一些简单应用,这是第一次写博客,有很多不足的地方希望各位看客给出宝贵建议,另外本文写的不对的地方,请各位大神勿喷!!!
很多人都会在各个系统里面遇到发送邮件的功能,这次开博写文章也是在整理过程中发现,团队中有个新来的小童鞋对发送邮件这块不是很熟,所以自己准备写一个简单的样例。
这里加了一个消息队列主要是用于高并发的情况下,对邮件发送的控制,并可以对消息进行缓存,防止消息丢失。
话不多说直接上代码:
用maven对项目进行的管理,pom.xml
<dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency>
邮件实体:
package com.test.utils.mail; import java.io.Serializable; /** * * @author * */ public class MailVo { /** * 注释内容 */ private static final long serialVersionUID = 1L; private String receiver; private String subject; private String content; public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public static long getSerialversionuid() { return serialVersionUID; } }
邮件基本配置config.properties
#mail smtp host mail.smtp.host = smtp.exmail.qq.com mail.smtp.port = 465 mail.smtp.username = test mail.sender = [email protected] mail.smtp.password = test
很多人用的是多线程来做的这个地方,我考虑了下,我觉得用队列比较合适,因为如果有大量需要发送邮件的时候,新建太多的线程会对系统产生不必要的开销,虽然可以集合线程池的方式来做,当然如果是邮件业务比较多,多线程的并发会好点。
我考虑了下,有时候邮件业务不是很多,所以,我给单线程加了个状态维护,在3分钟内没有任务,则销毁该线程,等待新的任务再重新创建新的线程。
package com.test.utils.mail; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; /** * 邮件发送管理插件 * 主要用于管理邮件队列和发送邮件 * @author * */ public class SendMailManager{ private static Logger logger = Logger.getLogger(SendMailManager.class); //缓存发送邮件的队列 public static BlockingQueue<MailVo> queue = new ArrayBlockingQueue<MailVo>(2000); //发送邮件线程状态 private static boolean isRunning = false; //超时时间间隔 public static long TIMEOUT_INTERVAL = 3*60*1000; public static boolean sendMail(MailVo mail){ boolean rsp = false; try { //阻塞3秒 rsp = queue.offer(mail, 3, TimeUnit.SECONDS); if(!rsp){ throw new Exception("服务器发送邮件繁忙,请稍后再发"); } if(!isRunning){ startup(); isRunning = true; } } catch (Exception e) { logger.error("添加发送邮件队列出错", e); } return rsp; } public static void startup(){ if(isRunning){ return; } Thread th = new Thread(){ @Override public void run(){ logger.debug("邮件发送消息线程启动"); long timestamp = System.currentTimeMillis(); while(isRunning) { long timeout = timestamp + TIMEOUT_INTERVAL; if(System.currentTimeMillis()>timeout) { //空跑一段时间(3分钟)后线程退出 break; } try { if(queue.size()==0) { Thread.sleep(1000); continue; } timestamp = System.currentTimeMillis(); MailVo mail = queue.poll(); MailUtil.sendMail(mail); //发送一个邮件休息2秒,防止发送过快,导致主油箱被锁定 Thread.sleep(2000); } catch (Exception e) { logger.error("邮件推送线程出错",e); } } isRunning = false; logger.debug("邮件发送线程停止。"); } }; th.start(); } }
邮件发送工具:
package com.test.utils.mail; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.List; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeUtility; import org.apache.log4j.Logger; import org.springframework.util.StringUtils; import com.sun.mail.smtp.SMTPSendFailedException; import com.sun.mail.util.MailSSLSocketFactory; import com.test.constant.Config; import com.test.utils.PropUtil; /** * @描述: * * @author 作者 : * */ public class MailUtil { private static Logger logger = Logger.getLogger(MailUtil.class); public static boolean sendMail(MailVo mailVo){ boolean flag = false; PropUtil pro = new PropUtil(Config.CONFIG_PATH); String smtpHost = ""; String smtpport = ""; String from = ""; String password = ""; String to = ""; String subject = ""; String messageText = ""; try { smtpHost = pro.getValue(Config.MAIL_SMTP_HOST); smtpport = pro.getValue(Config.MAIL_SMTP_PORT); from = pro.getValue(Config.MAIL_SENDER); password = pro.getValue(Config.MAIL_SMTP_PASSWORD); to = mailVo.getReceiver(); subject = mailVo.getSubject(); messageText = mailVo.getContent(); int sendFlag = sendMessage(smtpHost, smtpport, from, password, to, subject, messageText); flag = true; if(sendFlag == 200){ logger.debug("邮件发送成功:发件人 = " + from + "; 收件人 = " + to + "; 主题 = " + subject + "; 内容 = " + messageText); }else{ logger.debug("邮件发送失败:发件人 = " + from + "; 收件人 = " + to + "; 主题 = " + subject + "; 内容 = " + messageText); } } catch (Exception e) { logger.debug("发送邮件失败,失败内容:smtpHost = " + smtpHost); logger.debug("发送邮件失败,失败内容:smtpport = " + smtpport); logger.debug("发送邮件失败,失败内容:from = " + from); logger.debug("发送邮件失败,失败内容:password = " + password); logger.debug("发送邮件失败,失败内容:to = " + to); logger.debug("发送邮件失败,失败内容:smtpHost = " + smtpHost); logger.debug("发送邮件失败,失败内容:subject = " + subject); logger.debug("发送邮件失败,失败内容:messageText = " + messageText); logger.error("发送邮件失败", e); } return flag; } public static int sendMessage(String smtpHost,String smtpport, String from, String password, String to, String subject, String messageText){ try { //1、配置邮件基本属性 java.util.Properties props = new java.util.Properties(); //2、判断是否需要开启SSL if(!StringUtils.isEmpty(smtpport) && smtpport.equals("465")){ MailSSLSocketFactory sf; try { sf = new MailSSLSocketFactory(); sf.setTrustAllHosts(true); props.put("mail.smtp.ssl.enable", "true"); //props.put("mail.smtp.ssl.checkserveridentity", "true"); props.put("mail.smtp.ssl.socketFactory", sf); } catch (GeneralSecurityException e1) { logger.error("开始SSL设置出错", e1); } } props.setProperty("mail.smtp.auth", "true");//指定是否需要SMTP验证 props.setProperty("mail.smtp.host", smtpHost);//指定SMTP服务器 props.setProperty("mail.smtp.port", smtpport);//指定SMTP服务器端口 props.put("mail.transport.protocol", "smtp"); Session mailSession = Session.getInstance(props); mailSession.setDebug(true);//是否在控制台显示debug信息 //3、构建发送邮件的具体消息体 logger.debug("Constructing message - from=" + from + " to=" + to); String nick = javax.mail.internet.MimeUtility.encodeText("邮件用户昵称,根据自己实际定义"); //设置发送人 InternetAddress fromAddress = new InternetAddress(nick+" <"+from+">"); //设置接收人 InternetAddress toAddress; toAddress = new InternetAddress(to); MimeMessage testMessage = new MimeMessage(mailSession); try { testMessage.setFrom(fromAddress); } catch (MessagingException e) { logger.error(e); return 535; } try { testMessage.addRecipient(javax.mail.Message.RecipientType.TO, toAddress); } catch (MessagingException e) { logger.error(e); return 534; } testMessage.setSentDate(new java.util.Date()); testMessage.setSubject(MimeUtility.encodeText(subject,"gb2312","B")); //设置消息文本 testMessage.setContent(messageText, "text/html;charset=gb2312"); System.out.println("Message constructed"); Transport transport; transport = mailSession.getTransport("smtp"); //设置邮箱服务器 用户名 密码 transport.connect(smtpHost, from, password); transport.sendMessage(testMessage, testMessage.getAllRecipients()); transport.close(); return 200; }catch(SMTPSendFailedException e){ logger.error(e); return 550; }catch (MessagingException e) { logger.error(e); return 500; } catch (UnsupportedEncodingException e) { logger.error(e); return 501;//文本消息有错 } } }
本文是用的腾讯企业邮箱作为测试的,但是发现在测试过程中,很容易造成:
javax.mail.AuthenticationFailedException: 535 Error: authentication failed, system busy
用于登录失败,所以整理了下具体原因:
1:邮箱有独立密码,非邮箱登录密码
2:邮箱设置的客户端单独授权码
进入邮箱,点击设置:
额,第一次写文,话不多说,直接都是给的精华,希望初学者能理解到。
另外代码封装不是很好,主要是为了测试,请在自己项目中重新封装下,以便于程序的扩展。
时间: 2024-11-04 21:23:58