javaMail發送郵件

小弟今天爲了本身搭建的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);  
    }  
}

很簡單的

相關文章
相關標籤/搜索