JAVA项目四:邮件发送客户端

一、Java Mail API简介

JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Agent,简称MUA)。而不是像sendmail或者其它的邮件传输代理(Mail Transfer Agent,简称MTA)程序那样可以传送、递送、转发邮件。从另外一个角度来看,我们这些电子邮件用户日常用MUA程序来读写邮件,而MUA依赖着MTA处理邮件的递送。
JavaMail核心类:Session、Message、Address、Authenticator、Transport、Store、Folder。
Session类:定义了基本的邮件会话。就像Http会话那样,我们进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。
Message类: SUN提供了Message类型来帮助开发者完成这项工作。由于Message是一个抽象类,大多数情况下,我们使用javax.mail.internet.MimeMessage这个子类,该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US-ASCII字符,而非ASCII字符将通过编码转换为ASCII的方式使用
Address类:到这里,我们已经建立了Session和Message,下面将介绍如何使用邮件地址类:Address。像Message一样,Address类也是一个抽象类,所以我们将使用javax.mail.internet.InternetAddress这个子类。
Authenticator类:像java.net类那样,JavaMail API通过使用授权者类(Authenticator)以用户名、密码的方式访问那些受到保护的资源,在这里“资源”就是指邮件服务器。在javax.mail包中可以找到这个JavaMail的授权者类(Authenticator)。
Transport类:在发送信息时,Transport类将被用到。这个类实现了发送信息的协议(通称为SMTP),此类是一个抽象类,我们可以使用这个类的静态方法send()来发送消息:Transport.send(message);
Store和Folder类:接收邮件和发送邮件很类似都要用到Session。但是在获得Session后,我们需要从Session中获取特定类型的Store,然后连接到Store,这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码

ps:项目要用到jar包:activation.jar和mail.jar.

二、代码实现

项目源码下载地址:点我

package com.hnust.frame;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Date;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Transport;
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 javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class SendAttachmentMailFrame extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private JTextArea ta_attachment;
    private JTextArea ta_text;
    private JTextField tf_title;
    private JTextField tf_send;
    private JTextField tf_receive;
    private JPasswordField tf_password;
    /**
     * Session类是定义了一个基本会话,是Java Mail API最高层入口类。所有其他类都是经由这个Session才得以生效。
     * Session对象从java.util.Properties对象中获取信息,
     * 如邮件发送服务器、接收邮件协议、发送邮件协议、用户名、密码及整个应用程序中共享的其他信息
     * */
    private Session session;
    private String sendHost = "localhost";
    private String sendProtocol="smtp";
    private String filePathAndName = null;

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    SendAttachmentMailFrame frame = new SendAttachmentMailFrame();
                    frame.init();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public SendAttachmentMailFrame() {
        super();
        setTitle("发送带附件的邮件");
        getContentPane().setLayout(null); //设置布局为空布局
        setBounds(200, 200, 480, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JLabel label = new JLabel();
        label.setForeground(new Color(0, 0, 255));
        label.setFont(new Font("", Font.BOLD, 22));
        label.setText("@发送带附件的邮件@");
        label.setBounds(123, 10, 230, 24);
        getContentPane().add(label);

        final JLabel label_1 = new JLabel();
        label_1.setText("收件人地址:");
        label_1.setBounds(22, 42, 85, 18);
        getContentPane().add(label_1);

        tf_receive = new JTextField();
        tf_receive.setBounds(113, 40, 287, 22);
        getContentPane().add(tf_receive);

        final JLabel label_2 = new JLabel();
        label_2.setText("发件人邮箱:");
        label_2.setBounds(22, 68, 78, 18);
        getContentPane().add(label_2);

        tf_send = new JTextField();
        tf_send.setBounds(113, 66, 287, 22);
        getContentPane().add(tf_send);

        final JLabel label_2_1 = new JLabel();
        label_2_1.setText("邮箱密码:");
        label_2_1.setBounds(30, 95, 78, 18);
        getContentPane().add(label_2_1);

        tf_password = new JPasswordField();
        tf_password.setBounds(113, 95, 278, 18);
        getContentPane().add(tf_password);

        final JLabel label_3 = new JLabel();
        label_3.setText("主    题:");
        label_3.setBounds(32, 125, 66, 18);
        getContentPane().add(label_3);

        tf_title = new JTextField();
        tf_title.setBounds(113, 125, 287, 22);
        getContentPane().add(tf_title);

        final JLabel label_4 = new JLabel();
        label_4.setText("正    文:");
        label_4.setBounds(34, 150, 66, 18);
        getContentPane().add(label_4);

        //创建一个空的(无视口的视图)JScrollPane,需要时水平和垂直滚动条都可显示
        final JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBounds(113, 150, 287, 76);
        getContentPane().add(scrollPane);

        ta_text = new JTextArea();
        //创建一个视口(如果有必要)并设置其视图
        scrollPane.setViewportView(ta_text);

        final JButton btn_send = new JButton();
        btn_send.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                String fromAddr = tf_send.getText().trim();
                String toAddr = tf_receive.getText().trim();// 真实存在的目标邮件地址
                String title = tf_title.getText().trim();
                String text = ta_text.getText().trim();
                try {
                  sendMessage(fromAddr, toAddr, title, text);   //发送消息
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        });
        btn_send.setText("发    送");
        btn_send.setBounds(225, 300, 85, 28);
        getContentPane().add(btn_send);//添加发送按钮到容器

        final JButton btn_exit = new JButton();
        btn_exit.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                System.exit(0);
            }
        });
        btn_exit.setText("退    出");
        btn_exit.setBounds(316, 300, 84, 28);
        getContentPane().add(btn_exit);

        final JButton button = new JButton();   //添加附件按钮
        button.addActionListener(new ActionListener() { //点击事件
            public void actionPerformed(final ActionEvent e) {
                JFileChooser fileChooser = new JFileChooser(); // 创建文件对话框
                int returnValue = fileChooser.showOpenDialog(null);// 打开文件选择对话框
                if (returnValue == JFileChooser.APPROVE_OPTION) { // 判断是否选择了文件
                    File file = fileChooser.getSelectedFile(); // 获得文件对象
                    if (file.length() / 1024.0 / 1024 > 50.0) {
                        JOptionPane.showMessageDialog(null, "请选择小于等于50MB的文件。");
                        return;
                    }
                    filePathAndName = file.getAbsolutePath();// 获得文件的完整路径和文件名
                    ta_attachment.append(file.getName());// 显示附件文件的名称
                }
            }
        });
        button.setText("添加附件");
        button.setBounds(113, 300, 106, 28);
        getContentPane().add(button);

        final JLabel label_5 = new JLabel();
        label_5.setText("附    件:");
        label_5.setBounds(32, 230, 66, 18);
        getContentPane().add(label_5);

        //创建一个空的(无视口的视图)JScrollPane,需要时水平和垂直滚动条都可显示
        final JScrollPane scrollPane_1 = new JScrollPane();
        scrollPane_1.setBounds(112, 230, 287, 63);
        getContentPane().add(scrollPane_1);

        ta_attachment = new JTextArea();
        //创建一个视口(如果有必要)并设置其视图
        scrollPane_1.setViewportView(ta_attachment);
    }
    public void init() throws Exception {
        /**
         * Session对象利用Properties对象获得了邮件发送服务器、接收邮件协议、发送邮件协议、用户名、密码等整个应用程序都要使用到的共享信息
         * */
        Properties props = new Properties();
        /**
         *  put()方法将指定 key 映射到此哈希表中的指定 value。键和值都不可以为 null。 
            通过使用与原来的键相同的键调用 get 方法,可以获取相应的值
         * */
        props.put("mail.transport.protocol", sendProtocol);//发送协议
        props.put("mail.smtp.class", "com.sun.mail.smtp.SMTPTransport");
        props.put("mail.smtp.host", "127.0.0.1");//本机地址和域名绑定。否则会出错 详见:http://www.cnblogs.com/zhongzheng123/p/5869554.html
        session = Session.getDefaultInstance(props);
    }
    /**
     * @param fromAddr 发送方地址
     * @param toAddr 接收方地址
     * @param title 主题
     * @param text 文本内容
     * @throws Exception 异常
     */
    public void sendMessage(String fromAddr,String toAddr,String title,String text) throws Exception {
        //Message类封装的邮件信息,提供了访问和设置邮件内容的方法
        Message msg = new MimeMessage(session);// 创建Message对象
        /**
         * 建立了Session和Message对象之后,使用邮件地址Address抽象类的子类:javax.mail.internetAddress 
         * */
        InternetAddress[] toAddrs = InternetAddress.parse(toAddr,false);// 接收方地址
        msg.setRecipients(Message.RecipientType.TO, toAddrs);// 指定接收方
        msg.setSentDate(new Date());// 设置发送日期
        msg.setSubject(title);// 设置主题
        msg.setFrom(new InternetAddress(fromAddr));// 设置发送地址

        Multipart multipart = new MimeMultipart();// 可以添加复杂内容的Multipart对象(Multipart抽象类是保存电子邮件内容的容器)
        MimeBodyPart mimeBodyPartText = new MimeBodyPart();// 添加正文的MimeBodyPart对象
        mimeBodyPartText.setText(text);// 指定正文
        multipart.addBodyPart(mimeBodyPartText);// 添加到Multipart对象上
        if (filePathAndName!=null && !filePathAndName.equals("")){
            MimeBodyPart mimeBodyPartAdjunct = new MimeBodyPart();// 添加附件的MimeBodyPart对象
            FileDataSource fileDataSource = new FileDataSource(filePathAndName);// 创建附件的FileDataSource对象
            mimeBodyPartAdjunct.setDataHandler(new DataHandler(fileDataSource));// 指定数据
            mimeBodyPartAdjunct.setDisposition(Part.ATTACHMENT);// 指定添加的内容是附件
            String name = fileDataSource.getName();
            mimeBodyPartAdjunct.setFileName(MimeUtility.encodeText(name, "GBK", null));// 指定附件文件的名称
            multipart.addBodyPart(mimeBodyPartAdjunct);// 添加到Multipart对象上
        }
        msg.setContent(multipart);// 设置邮件内容
        String server = "smtp.163.com";  //设置SMTP服务器(220.181.12.15)
        String username = tf_send.getText();  //获取发送方的邮箱用户名
        String password = new String(tf_password.getPassword());    //获取发送方的邮箱密码
        /**
         * Transport类根据指定的邮件发送协议(通常是SMTP),通过指定的邮件发送服务器来发送邮件。
         * Transport类是抽象类,他提供了一个静态方法send(Message)来发送邮件
         * */       
        Transport transport = session.getTransport();  
        transport.connect(server, username, password);  //连接服务器
        transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO)); //发送邮件
        filePathAndName = null;
        JOptionPane.showMessageDialog(null, "邮件发送成功。");
    }
}

运行效果:

三、遇到的问题

1、Could not connect to SMTP host: localhost, port: 25;

问题原因:SMTP服务主机没有正确配置
解决办法:配置正确的SMTP服务主机,保证服务连接上

 String server = "smtp.163.com";  //设置SMTP服务器(220.181.12.15)
        String username = tf_send.getText();  //获取发送方的邮箱用户名
        String password = new String(tf_password.getPassword());    //获取发送方的邮箱密码
        /**
         * Transport类根据指定的邮件发送协议(通常是SMTP),通过指定的邮件发送服务器来发送邮件。
         * Transport类是抽象类,他提供了一个静态方法send(Message)来发送邮件
         * */       
        Transport transport = session.getTransport();  
        transport.connect(server, username, password);  //连接服务器
        transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO)); //发送邮件

灵感来自博客:解决办法

2、邮箱要开启SMTP服务,否则会导致无法发送邮件或者邮件会被存入垃圾箱。百度一下就能找到邮箱开启SMTP的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章