小弟今天爲了本身搭建的activeMQ 作了一個郵件測試。結果非常鬱悶。什麼緣由呢java
由於本來打算使用QQ給本身的QQ發個郵件就行的。誰曾想,一直報535錯誤(用戶名與密碼不匹配)spring
排查了很久,後來換成163郵箱發送給QQ 結果成功了。什麼都沒有改。這就鬱悶了。結果在各位大牛的思路下,外加參考http://blog.csdn.net/nijiayy/article/details/51267837 博客的內容。修改了一些配置終於成功了。apache
大部分都是使用java代碼寫的sendMail ,我是隻用spring直接加載的。代碼以下api
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd"> <!-- Spring提供的發送電子郵件的高級抽象類 --> <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="${mail.host}" /> <property name="username" value="${mail.username}" /> <property name="password" value="${mail.password}" /> <property name="defaultEncoding" value="UTF-8"></property> <property name="javaMailProperties"> <props> <prop key="mail.smtp.auth">${mail.smtp.auth}</prop> <prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop> <prop key="mail.smtp.ssl.enable">${mail.smtp.ssl.enable}</prop> <prop key="mail.smtp.socketFactory.class">${mail.smtp.socketFactory.class}</prop> </props> </property> </bean> <bean id="simpleMailMessage" class="org.springframework.mail.SimpleMailMessage"> <property name="from"> <value>${mail.default.from}</value> </property> </bean> <!-- 配置線程池 --> <bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 線程池維護線程的最少數量 --> <property name="corePoolSize" value="5" /> <!-- 線程池維護線程所容許的空閒時間 --> <property name="keepAliveSeconds" value="30000" /> <!-- 線程池維護線程的最大數量 --> <property name="maxPoolSize" value="50" /> <!-- 線程池所使用的緩衝隊列 --> <property name="queueCapacity" value="100" /> </bean> </beans>
總結以下:session
一、若是想使用QQ發送郵件,就須要使用QQ在開通stmp協議後提供的受權碼(163等其餘郵箱未必須要)。異步
二、JavaMailSenderImpl實現類中的host爲smtp.qq.com 非smtp.exmail.qq.com ;socket
三、port爲465 不用默認的25;工具
四、老版本QQ郵箱沒有SSL協議,截止到我寫這個文章的時候它已經支持了SSL協議。因此,在JavaMailSenderImpl的屬性javaMailProperties 中在加幾個支持ssl協議的參數:測試
分別是:<prop key="mail.smtp.ssl.enable">true</prop>
<prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>this
若是沒有加上述的SSL協議支持的話,運行時會出現5XX異常,說是要求使用ssl協議傳輸。
若是沒有受權碼,會報5XX異常,爲用戶名與密碼不匹配;
五、main方法很簡單
public class MQConsumer { private static final Log log = LogFactory.getLog(MQConsumer.class); public static void main(String[] args) { try { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml"); context.start(); } catch (Exception e) { log.error("==>MQ context start error:", e); System.exit(0); } } }
以上是消費方的部分代碼。下面是生產者的代碼。
固然了。由於我是使用MQ的。因此還會有發送方。和注意&內容等參數,以下:
public class MQProducerTest { private static final Log log = LogFactory.getLog(MQProducerTest.class); public static void main(String[] args) { try { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml"); context.start(); MQProducer mqProducer = (MQProducer) context.getBean("mqProducer"); // 郵件發送 MailParam mail = new MailParam(); mail.setTo("252276549@qq.com"); mail.setSubject("ActiveMQ測試"); mail.setContent("經過ActiveMQ異步發送郵件!"); mqProducer.sendMessage(mail); context.stop(); } catch (Exception e) { log.error("==>MQ context start error:", e); System.exit(0); } finally { log.info("===>System.exit"); System.exit(0); } } }
MqProducer的代碼以下
@Service("mqProducer") public class MQProducer { @Autowired private JmsTemplate activeMqJmsTemplate; /** * 發送消息. * @param mail */ public void sendMessage(final MailParam mail) { activeMqJmsTemplate.send(new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createTextMessage(JSONObject.toJSONString(mail)); } }); } }
MailParam類以下:
public class MailParam { /** 發件人 **/ private String from; /** 收件人 **/ private String to; /** 主題 **/ private String subject; /** 郵件內容 **/ private String content; public MailParam() { } public MailParam(String to, String subject, String content) { this.to = to; this.subject = subject; this.content = content; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } 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; } }
MailParam和MqProducer 是消息生產者的兩個封裝類。爲了避免給你們增長理解上的煩惱這裏把源碼貼出來。
這樣就能夠把消息經過JMS的api發送到消息中間件裏了。
在消息消費者的代碼中,也有一個main,以下
public class MQConsumer { private static final Log log = LogFactory.getLog(MQConsumer.class); public static void main(String[] args) { try { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml"); context.start(); } catch (Exception e) { log.error("==>MQ context start error:", e); System.exit(0); } } }
spring的消費者完整配置以下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" default-autowire="byName" default-lazy-init="false"> <!-- 採用註釋的方式配置bean --> <context:annotation-config /> <!-- 配置要掃描的包 --> <context:component-scan base-package="wusc.edu.demo" /> <!-- 讀入配置屬性文件 --> <context:property-placeholder location="classpath:mq.properties,classpath:mail.properties" /> <!-- proxy-target-class默認"false",更改成"ture"使用CGLib動態代理 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <import resource="spring-mq.xml" /> <import resource="spring-mail.xml" /> </beans>
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd"> <!-- Spring提供的發送電子郵件的高級抽象類 --> <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="${mail.host}" /> <property name="username" value="${mail.username}" /> <property name="password" value="${mail.password}" /> <property name="defaultEncoding" value="UTF-8"></property> <property name="javaMailProperties"> <props> <prop key="mail.smtp.auth">${mail.smtp.auth}</prop> <prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop> <prop key="mail.smtp.ssl.enable">${mail.smtp.ssl.enable}</prop> <prop key="mail.smtp.socketFactory.class">${mail.smtp.socketFactory.class}</prop> </props> </property> </bean> <bean id="simpleMailMessage" class="org.springframework.mail.SimpleMailMessage"> <property name="from"> <value>${mail.default.from}</value> </property> </bean> <!-- 配置線程池 --> <bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 線程池維護線程的最少數量 --> <property name="corePoolSize" value="5" /> <!-- 線程池維護線程所容許的空閒時間 --> <property name="keepAliveSeconds" value="30000" /> <!-- 線程池維護線程的最大數量 --> <property name="maxPoolSize" value="50" /> <!-- 線程池所使用的緩衝隊列 --> <property name="queueCapacity" value="100" /> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" default-autowire="byName" default-lazy-init="false"> <!-- 真正能夠產生Connection的ConnectionFactory,由對應的 JMS服務廠商提供 --> <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <!-- ActiveMQ服務地址 --> <property name="brokerURL" value="${mq.brokerURL}" /> <property name="userName" value="${mq.userName}"></property> <property name="password" value="${mq.password}"></property> </bean> <!-- ActiveMQ爲咱們提供了一個PooledConnectionFactory,經過往裏面注入一個ActiveMQConnectionFactory 能夠用來將Connection、Session和MessageProducer池化,這樣能夠大大的減小咱們的資源消耗。 要依賴於 activemq-pool包 --> <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"> <property name="connectionFactory" ref="targetConnectionFactory" /> <property name="maxConnections" value="${mq.pool.maxConnections}" /> </bean> <!-- Spring用於管理真正的ConnectionFactory的ConnectionFactory --> <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory"> <!-- 目標ConnectionFactory對應真實的能夠產生JMS Connection的ConnectionFactory --> <property name="targetConnectionFactory" ref="pooledConnectionFactory" /> </bean> <!-- Spring提供的JMS工具類,它能夠進行消息發送、接收等 --> <!-- 隊列模板 --> <bean id="activeMqJmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <!-- 這個connectionFactory對應的是咱們定義的Spring提供的那個ConnectionFactory對象 --> <property name="connectionFactory" ref="connectionFactory"/> <property name="defaultDestinationName" value="${queueName}"></property> </bean> <!--這個是sessionAwareQueue目的地 --> <bean id="sessionAwareQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg> <value>${queueName}</value> </constructor-arg> </bean> <!-- 能夠獲取session的MessageListener --> <bean id="consumerSessionAwareMessageListener" class="wusc.edu.demo.mqtest.listener.ConsumerSessionAwareMessageListener"></bean> <bean id="sessionAwareListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="destination" ref="sessionAwareQueue" /> <property name="messageListener" ref="consumerSessionAwareMessageListener" /> </bean> </beans>
在消費者的main一啓動,會加載spring中的監聽器,此監聽器是自定義的,
@Component public class ConsumerSessionAwareMessageListener implements SessionAwareMessageListener<Message> { private static final Log log = LogFactory.getLog(ConsumerSessionAwareMessageListener.class); @Autowired private JmsTemplate activeMqJmsTemplate; @Autowired private Destination sessionAwareQueue; @Autowired private MailBiz bailBiz; public synchronized void onMessage(Message message, Session session) { try { ActiveMQTextMessage msg = (ActiveMQTextMessage) message; final String ms = msg.getText(); log.info("==>receive message:" + ms); MailParam mailParam = JSONObject.parseObject(ms, MailParam.class);// 轉換成相應的對象 if (mailParam == null) { return; } try { bailBiz.mailSend(mailParam); } catch (Exception e) { // 發送異常,從新放回隊列 // activeMqJmsTemplate.send(sessionAwareQueue, new MessageCreator() { // public Message createMessage(Session session) throws JMSException { // return session.createTextMessage(ms); // } // }); log.error("==>MailException:", e); } } catch (Exception e) { log.error("==>", e); } } }
此監聽器實現了spring默認的監聽器,並在消息隊列中找到相同的名字,後就會啓動onMessage,將消息進行邏輯處理。bailBiz代碼以下:
@Component("mailBiz") public class MailBiz { @Autowired private JavaMailSender mailSender;// spring配置中定義 @Autowired private SimpleMailMessage simpleMailMessage;// spring配置中定義 @Autowired private ThreadPoolTaskExecutor threadPool; /** * 發送模板郵件 * * @param mailParamTemp須要設置四個參數 * templateName,toMail,subject,mapModel * @throws Exception * */ public void mailSend(final MailParam mailParam) { threadPool.execute(new Runnable() { public void run() { try { simpleMailMessage.setFrom(simpleMailMessage.getFrom()); // 發送人,從配置文件中取得 simpleMailMessage.setTo(mailParam.getTo()); // 接收人 simpleMailMessage.setSubject(mailParam.getSubject()); simpleMailMessage.setText(mailParam.getContent()); mailSender.send(simpleMailMessage); } catch (MailException e) { throw e; } } }); } }
到這裏就發送完成了。一些spring加載mq的源碼,還有spring是怎麼按照名字找消息的。源碼,小弟還在研究。後續補發。
這裏補貼一個java代碼發送郵件的代碼
@Component("sendemail") public class SendEmail { private JavaMailSenderImpl email; private SimpleMailMessage message; public SendEmail() { // TODO Auto-generated constructor stub email = new JavaMailSenderImpl(); email.setHost("smtp.qq.com"); email.setUsername("xxxxxx@qq.com"); email.setPassword("xxxxxxx");//受權碼 email.setPort(465); Properties properties = new Properties(); properties.put("mail.smtp.auth", true); properties.put("mail.smtp.ssl.enable", true); properties.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory"); properties.put("mail.smtp.timeout", 25000); email.setJavaMailProperties(properties); } //發送郵件 public void send(){ message = new SimpleMailMessage(); message.setFrom("xxxxxx@qq.com"); message.setTo("xxxxxx@gmail.com"); message.setSubject("WOW 郵箱激活"); message.setText("test"); email.send(message); } }
很簡單的