您的位置:首页 > 编程语言 > Java开发

邮件功能开发--JavaMail

2016-04-11 10:15 381 查看
本节摘要:本节主要简单介绍一下javamail插件的使用--转自月月鸟

引入:最近项目中要做一个简单的邮件功能,即从前台输入邮件内容,去配置文件中读取发件人、收件人等信息后,然后发送邮件到指定的邮箱,其中收件人和抄送人可以有多个,基于这个需求,查询了相关资料,决定采用javamail这个插件来实现。

preparation:

1.JavaMail的介绍

     JavaMail,顾名思义,提供给开发者处理电子邮件相关的编程接口。它是Sun发布的用来处理email的API。它可以方便地执行一些常用的邮件传输。

   虽然JavaMail是Sun的API之一,但它目前还没有被加在标准的java开发工具包中(Java Development Kit),这就意味着你在使用前必须另外下载JavaMail文件。除此以外,你还需要有Sun的JavaBeans Activation Framework (JAF)。JavaBeans Activation Framework的运行很复杂,在这里简单的说就是JavaMail的运行必须得依赖于它的支持。在Windows 2000下使用需要指定这些文件的路径,在其它的操作系统上也类似。

   JavaMail是可选包,因此如果需要使用的话你需要首先从java.sun.com下载。目前最新版本是JavaMail1.4,使用JavaMail的时候需要Javabean Activation Framework的支持,因此你也需要下载JAF。安装JavaMail只是需要把他们加入到CLASSPATH中去,如果你不想修改CLASSPATH的话,可以直接把他们的jar包直接copy到JAVA_HOME/lib/ext下。这样JavaMail就安装好了。
 
  JavaMail包中用于处理电子邮件的核心类是:Session,Message,Address,Authenticator,Transport,Store,Folder等。Session定义了一个基本的邮件会话,它需要从Properties中读取类似于邮件服务器,用户名和密码等信息
 

2.下载jar包

网上有下载链接,但是这里我还是把jar包给上传
javamail-1[1].4.2.zip
jaf-1_1_1.zip
dom4j.jar 这个jar就不提供下载资源了
 

3.项目环境

system:win7  myeclipse:6.5  tomcat:5.0 JDK:编译和运行都是1.4



为了方便,还是在之前的UpDown项目下运行的,本次用到的文件只有sendmail包下的文件。

 

4.javamail API class&method

请参考:http://www.jspcn.net/htmlnews/1150019680500144.html

 

start

导入javamail、JAF、dom4j的jar包,然后新建对应的文件如下:

Encrypt.jar  主要是用于对密码进行加密和解密

Encrypt.java

package sendmail;

/**

 * Module:      Encrypt.java

 * Description: 对密码进行加密和解密

 * Company:

 * Author:      ptp

 * Date:        Mar 6, 2012

 */

public class Encrypt

{

    public static final int pass1 = 10;

    public static final int pass2 = 1;

    public Encrypt()

    {

    }

    /**

     * @Title: DoEncrypt

     * @Description: 对密码进行加密的方法

     * @param @param str

     * @param @return    设定文件

     * @return String    返回类型

     * @throws

*/

    public static String DoEncrypt(String str)

    {

        StringBuffer enStrBuff = new StringBuffer();

        for (int i = 0; i < str.length(); i++)

        {

            int tmpch = str.charAt(i);

            tmpch ^= 1;

            tmpch ^= 0xa;

            enStrBuff.append(Integer.toHexString(tmpch));

        }

        return enStrBuff.toString().toUpperCase();

    }

    /**

     * @Title: DoDecrypt

     * @Description: 对密码进行解密的方法

     * @param @param str

     * @param @return    设定文件

     * @return String    返回类型

     * @throws

*/

    public static String DoDecrypt(String str)

    {

        String deStr = str.toLowerCase();

        StringBuffer deStrBuff = new StringBuffer();

        for (int i = 0; i < deStr.length(); i += 2)

        {

            String subStr = deStr.substring(i, i + 2);

            int tmpch = Integer.parseInt(subStr, 16);

            tmpch ^= 1;

            tmpch ^= 0xa;

            deStrBuff.append((char)tmpch);

        }

        return deStrBuff.toString();

    }

    public static void main(String args[])

    {

        String source = "123456";

        String s = DoEncrypt(source);

        System.out.println("de=" + s);

        

        source = DoDecrypt(s);

       
11d8a
System.out.println("en=" + source);

    }

}
 

MailInfo.java javabean定义邮件需要的字段以及对应的get和set方法

MailInfo.java

package sendmail;

/**

 *Module:       MailInfo.java

 *Description:  定义发送邮件的所有字段的javabean

 *Company:      

 *Author:       ptp

 *Date:         Mar 1, 2012

 */

public class MailInfo{

    private String host;// 邮件服务器域名或IP

    private String from;// 发件人

    private String to;// 收件人

    private String cc;// 抄送人

    private String username;// 发件人用户名

    private String password;// 发件人密码

    private String title;// 邮件的主题

    private String content;// 邮件的内容

    

    public String getHost() {

        return host;

    }

    public void setHost(String host) {

        this.host = host;

    }

    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 getCc() {

        return cc;

    }

    public void setCc(String cc) {

        this.cc = cc;

    }

    public String getUsername() {

        return username;

    }

    public void setUsername(String username) {

        this.username = username;

    }

    public String getPassword() {

        return password;

    }

    public void setPassword(String password) {

        this.password = password;

    }

    public String getTitle() {

        return title;

    }

    public void setTitle(String title) {

        this.title = title;

    }

    public String getContent() {

        return content;

    }

    public void setContent(String content) {

        this.content = content;

    }

    

}
 

MyAuthenticator.java 用于对邮件授权

MyAuthenticator.java

package sendmail;

/**

 *Module:       MailInfo.java

 *Description:  邮件授权类

 *Company:      

 *Author:       ptp

 *Date:         Mar 6, 2012

 */

import javax.mail.PasswordAuthentication;

public class MyAuthenticator extends javax.mail.Authenticator {

    private String strUser;

    private String strPwd;

    public MyAuthenticator(String user, String password) {

        this.strUser = user;

        this.strPwd = password;

    }

    protected PasswordAuthentication getPasswordAuthentication() {

        return new PasswordAuthentication(strUser, strPwd);

    }

}
 

SendMail.java 发送邮件的封装类

 先读取xml配置文件,然后解析xml文件,最后取得配置文件的值封装完成后发邮件

SendMail.java

package sendmail;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;

import java.util.Properties;

import javax.mail.Message;

import javax.mail.MessagingException;

import javax.mail.Session;

import javax.mail.Transport;

import javax.mail.internet.AddressException;

import javax.mail.internet.InternetAddress;

import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.dom4j.Document;

import org.dom4j.DocumentException;

import org.dom4j.DocumentHelper;

import org.dom4j.Element;

/**

 * Module:      SendMail.java

 * Description: 发送邮件

 * Company:

 * Author:      ptp

 * Date:        Mar 1, 2012

 */

public class SendMail {

    

    private static final Log log = LogFactory.getLog(SendMail.class);

    // 配置文件xml的路径

    private final static String XML_PATH = "src" + File.separator + "sendmail"

            + File.separator + "SendMail.xml";

    //xml文件中字段对应的javabean对象

    private static MailInfo mailInfo = new MailInfo();

    

    /**

     * <p>Title: readXML</p>

     * <p>Description:读取xml文件,把文件内容以字符串形式输出</p>

     * @param xmlPath 配置文件的路径

     * @return

     * @throws Exception

*/

    private String readXML(String xmlPath) throws Exception {

        log.debug("xmlPath="+xmlPath);

        

        String fileContent = "";

        File file = new File(xmlPath);

        if (file.isFile() && file.exists()) {

            try {

                InputStreamReader read = new InputStreamReader(

                        new FileInputStream(file), "UTF-8");

                BufferedReader reader = new BufferedReader(read);

                String line;

                try {

                    while ((line = reader.readLine()) != null) {

                        fileContent += line;

                    }

                    reader.close();

                    read.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            } catch (UnsupportedEncodingException e) {

                e.printStackTrace();

            } catch (FileNotFoundException e) {

                e.printStackTrace();

            }

        }else{

            throw new Exception("config目录下的配置文件SendMail.xml不存在,请检查");

        }

        log.debug("xml="+fileContent);

        return fileContent;

    }

    

    /**

     * <p>Title: parseXML</p>

     * <p>Description:发送邮件给指定的收件人和抄送人,同时进行一些简单的校验判断,如必填项的字段、type的值</p>

     * @param xml 配置文件的内容

     * @param type  邮件类型

*/

    private void parseXML(String xml, String type) {

        type=type.toLowerCase();//忽略type字段的大小写

        try {

            // 解析XML,获得doc对象

            Document doc = DocumentHelper.parseText(xml);

            // 判断type的值是否正确,type的值应是报文二级节点中的一个

            String flag = doc.getRootElement().element(type) + "";

            if (null == flag || flag.equals("null"))

                throw new DocumentException(

                        "传入的type值不对,type的值应是SendMail.xml报文中二级节点的一个,请查看文件然后重新传入type的值");

            // 设置主机名称

            Element hostEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/host");

            if (null == hostEle || "".equals(hostEle.getTextTrim())) {

                throw new DocumentException("邮件服务器域名或IP不能为空,请检查配置文件SendMail.xml");

            }

            mailInfo.setHost(hostEle == null ? "" : hostEle.getTextTrim());

            // 设置发件人

            Element fromEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/from");

            if (null == fromEle || "".equals(fromEle.getTextTrim())) {

                throw new DocumentException("发件人地址不能为空,请检查配置文件SendMail.xml");

            }

            mailInfo.setFrom(fromEle == null ? "" : fromEle.getTextTrim());

            // 设置邮件主题

            Element titleEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/title");

            mailInfo.setTitle(titleEle == null ? "" : titleEle.getTextTrim());

            // 设置收件人,对多个收件人的处理放在后面

            Element toEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/to");

            if (null == toEle || "".equals(toEle.getTextTrim())) {

                throw new DocumentException("收件人地址不能为空,请检查配置文件SendMail.xml");

            }

            mailInfo.setTo(toEle == null ? "" : toEle.getTextTrim());

            // 设置抄送,对多个抄送人的处理放在后面

            Element ccEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/cc");

            mailInfo.setCc(ccEle == null ? "" : ccEle.getTextTrim());

            

            //设置发件人用户名

            Element nameEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/username");

            if(null==nameEle||"".equals(nameEle.getTextTrim())){

                throw new DocumentException("发件人用户名不能为空,请检查配置文件SendMail.xml");

            }

            mailInfo.setUsername(nameEle == null ? "" : nameEle.getTextTrim());

            

            //设置发件人密码

            Element passEle = (Element) doc.selectSingleNode("/mail/" + type

                    + "/password");

            if(null==passEle||"".equals(passEle.getTextTrim())){

                throw new DocumentException("发件人密码不能为空,请检查配置文件SendMail.xml");

            }

            mailInfo.setPassword(passEle == null ? "" : passEle.getTextTrim());

        } catch (DocumentException e) {

            e.printStackTrace();

        }

    }

    

    /**

     * <p>Title: sendMailOfValidate</p>

     * <p>Description:发送邮件的方法,Authenticator类验证</p>

*/

    private void sendMailOfValidate() {

        Properties props = System.getProperties();

        props.put("mail.smtp.host", mailInfo.getHost());//设置邮件服务器的域名或IP

        props.put("mail.smtp.auth", "true");//授权邮件,mail.smtp.auth必须设置为true

        

        String password=mailInfo.getPassword();//密码

        try {

           password=Encrypt.DoDecrypt(password);//如果密码经过加密用此方法对密码进行解密

        } catch (NumberFormatException e1) {

          //如果密码未经过加密,则对密码不做任何处理

        }

        //传入发件人的用户名和密码,构造MyAuthenticator对象

        MyAuthenticator myauth = new MyAuthenticator(mailInfo.getUsername(),password);

        

        //传入props、myauth对象,构造邮件授权的session对象

        Session session = Session.getDefaultInstance(props, myauth);

        //将Session对象作为MimeMessage构造方法的参数传入构造message对象

        MimeMessage message = new MimeMessage(session);

        try {

            message.setFrom(new InternetAddress(mailInfo.getFrom()));//发件人

// 对多个收件人的情况进行处理,配置文件SendMail.xml中每个收件人之间必须用逗号隔开的

            if (mailInfo.getTo() != null && !"".equals(mailInfo.getTo())) {

                String to[] = mailInfo.getTo().split(",");

                for (int i = 0; i < to.length; i++) {

                    message.addRecipient(Message.RecipientType.TO,

                            new InternetAddress(to[i]));// 收件人

                }

            }

            // 对多个抄送人的情况进行处理,每个抄送人之间用逗号隔开的

            if (mailInfo.getCc() != null && !"".equals(mailInfo.getCc())) {

                String cc[] = mailInfo.getCc().split(",");

                for (int j = 0; j < cc.length; j++) {

                    message.addRecipient(Message.RecipientType.CC,

                            new InternetAddress(cc[j]));// 抄送

                }

            }

            message.setSubject(mailInfo.getTitle());// 主题

            

            message.setText(mailInfo.getContent());// 内容

            Transport.send(message);// 调用发送邮件的方法

        

            log.debug("邮件发送成功");

        } catch (AddressException e) {

            e.printStackTrace();

        } catch (MessagingException e) {

            e.printStackTrace();

        }

    }

    

    /**

     * <p>Title: sendMail</p>

     * <p>Description:外部程序调用的入口</p>

     * @param type 邮件的类型,目前有三种,即logmessage、checkmessage、ordermessage,type只能传这三个值中一个,传其他的任何值都不行

     * @param content 邮件的内容

     * @throws Exception

*/

    public void sendMail(String type,String content) throws Exception{

        log.debug("入参type="+type);

        log.debug("入参content="+content);

        if (null == type || "".equals(type) || null == content

                || "".equals(content)) {

            throw new Exception("方法的入参type和content字段的值都不能为空或null");

        }

        

        String xml=readXML(XML_PATH);//获得xml字符串

        

        parseXML(xml,type);//解析xml字符串,把对应字段的值放入到mailInfo对象中

        

        mailInfo.setContent(content);//设置发送的内容

        

        sendMailOfValidate();//发送邮件

        

    }

    /**

     * 为了方便直接用main方法测试

     * @param args

     * @throws Exception

*/

    public static void main(String args[]) throws Exception {

        SendMail mail = new SendMail();

        

        // type类型,根据此字段去配置文件SendMail.xml中匹配,然后发到相应的邮箱

        String type = "logmessage";

        

        // 邮件的内容,实际开发中这个内容是前台传到后台

        String content = "你好,欢饮使用JavaMail包开发邮件功能";

        

        // 在其他类中调用时只能看到sendMail方法,为了保护内部细节,其它的方法都声明为私有的

        mail.sendMail(type, content);

        //这个项目中没有日志文件,所以我打印一句话来告诉自己程序已经成功运行

        System.out.println("****success****");

    }

}
说明:代码中的校验可能不太严谨和全面,因为这个配置文件是由开发人员自己配置,并且对配置文件也有详细的介绍,所以代码中就省略去了许多的校验。

SendMail.xml 邮件配置文件

SendMail.xml

<?xml version="1.0" encoding="UTF-8"?><!-- 此处编码格式必须用UTF-8格式,这样和程序中的解码是统一的,不会出现乱码 -->

<mail>

    <logmessage><!--报文的二级节点,为了使传入的type值对大小写不限制,故此处必须用小写 -->

        <host>smtp.qq.com</host><!-- 邮件服务器域名或IP,必填项 -->

        <from>838045782@qq.com</from><!-- 发件人 ,必填项 -->

        <to>838045782@qq.com,taipeng0820@163.com</to><!-- 收件人,多个收件人之间用英文状态下的逗号隔开,必填项 -->

        <cc>838045782@qq.com</cc><!-- 抄送,多个抄送人之间用英文状态下的逗号隔开-->

        <title>test JavaMail</title><!-- 邮件主题-->

        <username>838045782@qq.com</username><!-- 发件人邮箱的用户名,即email的全地址,必填项 -->

        <password>123456</password><!-- 发件人邮箱的密码,像QQ邮箱如果设置了独立密码应输入独立密码,必填项,为了安全起见填写密码之前最好用Encrypt类的DoEncrypt方法加密 -->

    </logmessage>

    <checkmessage>

        <host></host>

        <from></from>

        <to></to>

        <cc></cc>

        <title></title>

        <username></username>

        <password></password>

    </checkmessage>

    <ordermessage>

        <host></host>

        <from></from>

        <to></to>

        <cc></cc>

        <title></title>

        <username></username>

        <password></password>

    </ordermessage>

</mail>
注意:密码是必填项,由于是介绍,我把自己的密码给删掉换成了123456,实际中需根据需要配置邮件服务器域名、发件人、收件人、抄送人、用户名和密码。

 

result

运行方式:执行运行SendMail.java类中的main方式就可以测试了,测试之前请按说明配置xml文件。

首次运行你可能会遇到以下的错误,所以note.txt文件就用来提供遇到的错误以及对应的解决方案

note.txt

java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream

 at javax.mail.Session.loadProvidersFromStream(Session.java:928)

 at javax.mail.Session.access$000(Session.java:174)

 at javax.mail.Session$1.load(Session.java:870)

 at javax.mail.Session.loadResource(Session.java:1084)

 at javax.mail.Session.loadProviders(Session.java:889)

 at javax.mail.Session.<init>(Session.java:210)

 at javax.mail.Session.getDefaultInstance(Session.java:299)

 at mail.SendMail.sendMail(SendMail.java:31)

 at mail.SendMail.main(SendMail.java:50)

Exception in thread "main"

解决方案:在myeclipse的安装目录下搜索javaee.jar,然后用压缩软件打开,删除javax下的mail文件夹

java.lang.NoClassDefFoundError: com/sun/activation/registries/LogSupport

 at javax.activation.MailcapCommandMap.<init>(MailcapCommandMap.java:140)

 at javax.activation.CommandMap.getDefaultCommandMap(CommandMap.java:61)

 at javax.activation.DataHandler.getCommandMap(DataHandler.java:153)

 at javax.activation.DataHandler.getDataContentHandler(DataHandler.java:611)

 at javax.activation.DataHandler.writeTo(DataHandler.java:315)

 at javax.mail.internet.MimeUtility.getEncoding(MimeUtility.java:264)

 at javax.mail.internet.MimeBodyPart.updateHeaders(MimeBodyPart.java:1299)

 at javax.mail.internet.MimeMessage.updateHeaders(MimeMessage.java:2071)

 at javax.mail.internet.MimeMessage.saveChanges(MimeMessage.java:2039)

 at javax.mail.Transport.send(Transport.java:119)

 at mail.SendMail.sendMailNoValidate(SendMail.java:48)

 at mail.SendMail.main(SendMail.java:96)

Exception in thread "main"

解决方案:在myeclipse的安装目录下搜索javaee.jar,然后用压缩软件打开,删除javax文件夹下的activation文件夹

javax.mail.SendFailedException: Sending failed;

  nested exception is:

 javax.mail.MessagingException: 503 Error: need EHLO and AUTH first !

 at javax.mail.Transport.send0(Transport.java:219)

 at javax.mail.Transport.send(Transport.java:81)

 at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMailNoValidate(SendMailServiceImpl.java:210)

 at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMail(SendMailServiceImpl.java:243)

 at com.asiainfo.bboss.sendmail.SendMailServiceImpl.main(SendMailServiceImpl.java:261)

解决方案:props.put("mail.smtp.auth", "true");

 

javax.mail.SendFailedException: Sending failed;

  nested exception is:

 javax.mail.AuthenticationFailedException

 at javax.mail.Transport.send0(Transport.java:219)

 at javax.mail.Transport.send(Transport.java:81)

 at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMailNoValidate(SendMailServiceImpl.java:211)

 at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMail(SendMailServiceImpl.java:244)

 at com.asiainfo.bboss.sendmail.SendMailServiceImpl.main(SendMailServiceImpl.java:262)

解决方案: MyAuthenticator myauth = new MyAuthenticator(mailInfo.getUsername(),password);

 

运行截图如下:

图1:myeclipse后台打印的结果 此项目下没有log4j.properties文件,故会有红色的信息,代码中的log也没有打印出来



 
图2:去我的QQ邮箱收信---收件箱列表



 

图3:去我的QQ邮箱收信---邮件内容



 

图4:去我的163邮箱收信---收件箱列表

确认已经收到邮件,因为163邮件显示的是本人的真实姓名,这里就不截图了。

 

图5:去我的163邮箱收信---邮件内容

确认已经收到邮件,因为163邮件显示的是本人的真实姓名,这里就不截图了。

 

以上只是对javamail插件一个小小的应用,此插件也可以做收信、转发、答复、上传附件等功能,

希望更多的朋友可以接触到javamail插件,权当做一次宣传了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: