1、 武汉长江工商学院 --工学院 项目名称: 简单邮件发送客户端 程序设计 学生姓名: 学 号: 班 级: 指导老师: 2012年6月12日 目 录 1.设计概述 1 2.电子邮件发送协议与技术 1 2.1 SMTP协议简介及通讯模型 1 2.2 Java Mail API介绍 2 3.邮件发送客户端程序总体设
2、计 3 3.1系统模块结构 3 3.2类的功能设计 3 3.2.1系统托盘类 3 3.2.2 账号设置类 4 3.2.3 邮件发送类 4 4.功能模块的实现 5 4.1 程序主界面的设计 5 4.2账号设置功能实现 6 4.3邮件发送功能实现 8 4.4附件发送实现 10 4.5系统托盘实现 10 5.程序测试 11 5.1 发送邮件程序账号设置测试 12 5.2发送电子邮件程序测试 12 5.3电子邮件程序系统托盘测试 14 设计小结 15 参考文献 16 附录1:SystemTrayTest类 17 附录2:MainSender类 19 附录3:Lo
3、ginDialog类 28 1.设计概述 电子邮件(electronic mail,简称E-mail,标志:@,也被大家昵称为“伊妹儿”)又称电子信箱、电子邮政,它是—种用电子手段提供信息交换的通信方式。是Internet应用最广的服务:通过网络的电子邮件系统,用户可以用非常低廉的价格(不管发送到哪里,都只需负担电话费和网费即可),以非常快速的方式(几秒钟之内可以发送到世界上任何你指定的目的地),与世界上任何一个角落的网络用户联系,这些电子邮件可以是文字、图像、声音等各种方式。同时,用户可以得到大量免费的新闻、专题邮件,并实现轻松的信息搜索。 电子邮件的处理有两大
4、部分组成:电子邮件在Internet上发送和接收的原理可以很形象地用我们日常生活中邮寄包裹来形容:当我们要寄一个包裹时,我们首先要找到任何一个有这项业务的邮局,在填写完收件人姓名、地址等等之后包裹就寄出而到了收件人所在地的邮局,那么对方取包裹的时候就必须去这个邮局才能取出。同样的,当我们发送电子邮件时,这封邮件是由邮件发送服务器(任何一个都可以)发出,并根据收信人的地址判断对方的邮件接收服务器而将这封信发送到该服务器上,收信人要收取邮件也只能访问这个服务器才能完成。 本系统使用Eclipse作为开发工具,开发一个电子邮件发送端应用程序。系统实现的功能主要有帐号设置,发送及添加附件,托盘程序等
5、 本例发送程序采取了与发送邮件服务器连接实现电子邮件的发送。用户在“收件人邮箱”所对应的对话框中输入收件人的Email地址,并在账号设置窗口所对的对话框中输入发信人的Email地址,设置好账号后,进入主对话框编辑信件的正文(本程序还可以发送附件,直接选择路径,就可以发送附件),然后单击“发送”按钮,便可完成电子邮件的发送。电子邮件发送成功,程序将弹出一个“发送成功”的消息对话框;若电子邮件发送失败,程序将给出失败的相关信息。 2.电子邮件发送协议与技术 2.1 SMTP协议简介及通讯模型 (SMTP:Simple Mail Transfer Protocol)即简单邮件传输协议,它
6、是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。它能够在传送中接力传送邮件,传送服务提供了进程间通信环境(IPCE),此环境可以包括一个网络,几个网络或一个网络的子网。理解到传送系统(或IPCE)不是一对一的是很重要的。进程可能直接和其它进程通过已知的IPCE通信。邮件是一个应用程序或进程间通信。邮件可以通过连接在不同IPCE上的进程跨网络进行邮件传送。更特别的是,邮件可以通过不同网络上的主机接力式传送。SMTP协议属于TCP/IP协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地。通过SMTP协议所指定的服务器,我们就可以把E-mail寄到收信人的服务器上了,整
7、个过程只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转你发出的电子邮件。 SMTP 是一种提供可靠且有效电子邮件传输的协议。SMTP是建模在 FTP 文件传输服务上的一种邮件服务,主要用于传输系统之间的邮件信息并提供来信有关的通知。 SMTP 独立于特定的传输子系统,而且仅要求一条可以保证传送数据单元顺序的通道且只需要可靠有序的数据流信道支持。SMTP 重要特性之一是其能跨越网络传输邮件,即“ SMTP邮件中继”。通常,一个网络可以由公用互联网上 TCP 可相互访问的主机、防火墙分隔的 TCP/IP 网络上 TCP 可相互访问的主机,及其它 LAN/W
8、AN 中的主机利用非 TCP 传输层协议组成。使用 SMTP ,可实现相同网络上处理机之间的邮件传输,也可通过中继器或网关实现某处理机与其它网络之间的邮件传输。 在这种方式下,邮件的发送可能经过从发送端到接收端路径上的大量中间中继器或网关主机。域名服务系统(DNS)的邮件交换服务器可以用来识别出传输邮件的下一跳 IP 地址。SMTP在传输文件过程中使用25号端口。 可大致用下面的图2-1来表示。 用户 发送SMTP 文件系统 接收SMTP 文件系统 SMTP命令 邮件内容 应答 图2-1 SMTP通信模型 2.2 Java Mail
9、 API介绍 一般情况下,在eclipse中,电子邮件程序的编写是主要是利用Java jdk1.7扩展包JavaMailAPI等及相关的SMTP等通信协议来实现的。随着现代软件业的发展,java提供了方便、简易、与服务器无关且稳固的电子邮件处理组件,使我们可以在程序开发语言中调用这些组件,利用很简单的语言实现功能强大的程序。JavaMail便是一个很好的电子邮件程序开发扩展组件。 JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Agent,简称MUA)
10、而不是像sendmail或者其它的邮件传输代理(Mail Transfer Agent,简称MTA)程序那样可以传送、递送、转发邮件。从另外一个角度来看,我们这些电子邮件用户日常用MUA程序来读写邮件,而MUA依赖着MTA处理邮件的递送。 JavaMail核心类:Session、Message、Address、Authenticator、Transport、Store、Folder。 Session类:定义了基本的邮件会话。就像Http会话那样,我们进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息
11、和整个应用程序都要使用到的共享信息。 Message类:当我们建立了Session对象后,便可以被发送的构造信息体了。在这里SUN提供了Message类型来帮助开发者完成这项工作。由于Message是一个抽象类,大多数情况下,我们使用javax.mail.internet.MimeMessage这个子类,该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US-ASCII字符,而非ASCII字符将通过编码转换为ASCII的方式使用。 Address类:到这里,我们已经建立了Session和Message,下面将介绍如何使用邮件地址类:Address。像Message一样,Add
12、ress类也是一个抽象类,所以我们将使用javax.mail.internet.InternetAddress这个子类。 Authenticator类:像类那样,JavaMail API通过使用授权者类(Authenticator)以用户名、密码的方式访问那些受到保护的资源,在这里“资源”就是指邮件服务器。在javax.mail包中可以找到这个JavaMail的授权者类(Authenticator)。 Transport类:在发送信息时,Transport类将被用到。这个类实现了发送信息的协议(通称为SMTP),此类是一个抽象类,我们可以使用这个类的静态方法send()来发送消息:Tran
13、sport.send(message); Store和Folder类:接收邮件和发送邮件很类似都要用到Session。但是在获得Session后,我们需要从Session中获取特定类型的Store,然后连接到Store,这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码或者Authenticator。 3.邮件发送客户端程序总体设计 3.1系统模块结构 电子邮件客户端主要由以下三个模块构成:发送邮件模块、系统托盘模块、账号设置模块。 其功能模块如图3-1所示: 电子邮件发送端程序 发送邮件 账号设置 系统托盘
14、 1)发送邮件模块:发送邮件,并可以添加附件。 2)账号设置模块:对发送方电子邮件账号进行设置。 3)系统托盘模块:在任务栏可以使程序有托盘功能。 3.2类的功能设计 3.2.1系统托盘类 Class SystemTrayTest{ //该类为系统托盘类,为了实现邮件程序的托盘功能。 PopupMenu popup = new PopupMenu(); //系统托盘菜单数组。 MenuItem[] mItem = { new MenuItem("账号设置"),new MenuItem("退
15、出程序") }; //点击鼠标邮件的菜单数组 SystemTray tray;表示桌面的系统托盘对象。 TrayIcon trayIcon; // TrayIcon 对象表示可以添加 到系统托盘的托盘图标。TrayIcon 可以包含工具提示(文本)、图像、弹出菜单 和一组与之关联的侦听器。 MailSender inst; //表示创建一个邮件发送类。 public SystemTrayTest() //该方法表示一个托
16、盘类的构造。 public void actionPerformed(ActionEvent e) //该方法表示鼠标触发事件,其中的参数为监视器变量。 } 3.2.2 账号设置类 Class LoginDialog{ //该类为账号设置类,主要实现了邮件系统的账号功能。 public static MailSender ms; //表示创建一个邮件发送类。 private JLabel pwdLabel; //表示创建用户密码的短文本字符串的显示区。 private JTextFiel
17、d userJT; //表示创建用户账号的输入区。 private JButton logoutJB; //表示创建一个按钮。 private JPasswordField pwdJP; //表示创建一个密码输入区。 private JLabel userLabel; //表示创建用户账号的短文本字符串的显示区。 public LoginDialog(MailSender frame) //该方
18、法表示账号设置类的一个构造 private void initGUI() //该方法表示一个图形界面的初始化。 private void logonJBMouseEntered(MouseEvent evt)//该方法以及接后的几个类似的方法都表示鼠标触发事件。 } 3.2.3 邮件发送类 Class MailSender{ //该类为邮件发送类,主要是实现了邮件发送等功能。 public LoginDialog dlg; // 登录对话框 private static Strin
19、g attachPath; // 附件路径 private static String mailAddr; // 发件人邮箱地址 private static String mailPwd; // 发件人邮箱密码 public boolean loginCheck; // 是否已登录 private JLabel fromLabel; // 显示发件人 private JButton loginJB;
20、private JLabel attachLabel; private JLabel stateLabel; // 邮件状态 private boolean hasAttach; // 是否有附件 private JButton attachJB; // 添加附件 private JTextField recieverJT; // @前面的邮箱地址 private JTextField smtpJT; // @后面的邮箱地址 private JTextField tittleJT; // 主题 private JTextArea textJTA; //
21、 内容 private JSeparator jSeparator1; // 分割线 private void initGUI() //图形界面的初始化方法 class PasswordAuthenticator extends Authenticator//密码输入方法 private void sendJBActionPerformed(ActionEvent evt)//邮件发送的详细方法 private String smtpAddressConfirm(String smtpAddr)//SMTP邮件地址确认方法
22、private void attachJBActionPerformed(ActionEvent evt)//添加附件的方法 } 4.功能模块的实现 4.1 程序主界面的设计 本次设计中,主要用到对话框Java图形界面。Java图形界面是实现应用程序人机交互的重要组成部分。它不但可以实现数据流的输入和输出,而且也可以移动和关闭对话框。 a.创建类MailSender. 首先,创建MailSender类,此类继承javax.swing.JFrame类。 b.创建initGUI方法 首先,设置窗口关闭方法,调用 setDefaultCloseOperation(WindowCon
23、stants.DISPOSE_ON_CLOSE)方法。然后设置布局。对各个图形组件进行创建。 主界面的实现如图4-1,创建一个图形界面,有输入框,输入监视器,还有各个按钮等。方便用户可以使用系统。 图4-1 图形界面的创建与实现图 4.2账号设置功能实现 在账号设置时新建一个类,此类包含了GUI,鼠标触发事件,以及账号名,密码与邮件服务器的验证。在用户输入账号时会进行账号名检测,查看输入的账号格式是否有误,若有误,则返回重新输入。 账号设置流程图如图4-2,账号设置会在输入账号时检验合法性,然后等待主界面调用并提取账号。 输入邮箱账号(程序会检测账号合法性)以及密码,然后点
24、击“确定”按钮 点击“账号设置”按钮 程序提取账号,发送时与邮件服务器验证 等待发送 图4-2 账号设置流程图 部分此类代码如下: private void initGUI() { try { { this.setTitle("账号设置"); getContentPane().setLayout(null); } this.setBounds(450, 250, 300, 200); } private String smtpAddressConfirm(String smtpAddr) { if (smtpAdd
25、r.contains(".com")) { if (smtpAddr.contains("163")) { smtpAddr = ""; } else if (smtpAddr.contains("qq")) { smtpAddr = ""; } else { return "not include"; } } else { return "not include"; } return smtpAddr; } 4.3邮件发送功能实现 邮件发送流程图如图4-3,发送邮件时会对邮件以及账号进行处理和
26、验证。 获取收件人地址(验证地址合法性) 发往SMTP服务器进行验证 返回失败信息 验证失败 验证成功 获取发件人账号和密码传入服务器 发送邮件 输出对话框:发送成功 返回失败信息 发送失败 发送成功 图4-3 邮件发送流程图 1)获取收件人账号,并设置SMTP邮件服务器(程序会检测输入账号合法性)。 关键代码: String to = recieverJT.getText().trim() + "@" + smtpJT.getText().trim();// 获得收件人地址 System.out.prin
27、tln(to); String subject = tittleJT.getText(); String body = textJTA.getText(); Properties props = System.getProperties(); // 设置SMTP邮件服务器: String smtpAddr = smtpAddressConfirm(smtpJT.getText()); if ("not include" == smtpAddr) { JOptionPane.showMessageDialog(
28、null, "无法解析邮箱地址!"); jLabel1.setIcon(resources.error); } System.out.println(smtpAddr); props.put("mail.smtp.host", smtpAddr); props.setProperty("mail.smtp.port", "25"); // SMTP服务器需要验证: props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.
29、starttls.enable", "true"); props.put("mail.smtp.auth", "true"); 2)获取账号设置界面中用户输入的账号和密码传入服务器,然后创建一封新邮件。 关键代码: // 传入用户名和口令: Session session = Session.getDefaultInstance(props, new PasswordAuthenticator(mailAddr, mailPwd)); session.setDebug(true); // 创建新邮件: Mes
30、sage msg = new MimeMessage(session); msg.setFrom(new InternetAddress(mailAddr)); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); msg.setSubject(subject); msg.setText(body); msg.setSentDate(new Date()); 3)邮件发送以及发送失败的详细信息和原因。 关键代码:
31、 MimeBodyPart mbp1 = new MimeBodyPart(); mbp1.attachFile("sss"); Multipart multi = new MimeMultipart(); FileDataSource fds = new FileDataSource(attachPath); mbp1.setDataHandler(new DataHandler(fds)); mbp1.setFileName(attachLabel.getText()); multi.addBodyPart(mbp1); msg.setContent(mult
32、i); msg.saveChanges(); Transport.send(msg); System.out.println("mail sended!"); stateLabel.setText("发送成功!"); sendJB.setIcon(resources.ok); setIconImage(resources.mail_sended.getImage()); } catch (Exception ex) { JOptionPane.showMessageDialog(null, "发送邮件失败!"); System.err.println
33、"邮件发送失败的原因是:" + ex.getMessage()); System.err.println("具体的错误原因"); ex.printStackTrace(System.err); 4.4附件发送实现 添加附件流程图如图4-4,当用户点击“添加附加”按钮时,会弹出图形界面,方便用户选择附件路径,附件与邮件一起发送。 用户点击“添加附件”按钮 弹出界面,用户选择附件路径 有无多个附件? 有 无 等待与邮件一起发送 图4-4 添加附件流程图 新建一个JFileChoose对象chooser,然后调用对象的方法。 关键代码: ch
34、ooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setDialogTitle("打开文件夹"); chooser.setCurrentDirectory(new File("E:/flie/my coding tip")); chooser.setMultiSelectionEnabled(true);// 支持多个附件 int returnVal = chooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OP
35、TION) { attachPath = chooser.getSelectedFile().getAbsolutePath(); attachLabel.setIcon(resources.attach); attachLabel.setText(chooser.getSelectedFile().getName()); } this.setIconImage(resources.mail_attachment.getImage()); this.hasAttach = true; // 有附件 4.5系统托盘实现 系统托盘流程图如图4-5,功能
36、为当用户点击close键时,本系统最小化到托盘,然后当用户双击托盘图标时又出现主界面。 用户点击关闭按钮时本系统最小到系统托盘 鼠标点击 双击 点击右键选择账号设置 主界面出现 点击右键选择退出程序 退出程序 账号设置界面出现 图4-5 系统托盘流程图 在本程序中添加了系统托盘功能,使用了jdk1.6中新增加的类Systemtray和TrayIcon类创建系统托盘,并在托盘上增加了鼠标邮件菜单。 关键代码: trayIcon.addActionListener(this); trayIcon.addMouseListener(new M
37、ouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getSource() == trayIcon && e.getButton() == MouseEvent.BUTTON1) { if (flag) { setState(1); flag = false; } else { setState(0); flag = true; } } setVisi
38、ble(true); } 5.程序测试 现在,以发送如下的一封带附件的邮件来进行功能测试。 收件人:hubeigongpeng@ 发件人:hubeiwangchangyou@ 邮件主题:测试邮件,收到勿回 邮件内容:测试邮件,收到勿回 附件:测试文件.doc 5.1 发送邮件程序账号设置测试 测试开始,在账号输入框中输入账号hubeiwangchangyou@,在密码框中输入密码,然后点击确认按钮。 如图5-1所示,为输入账号和密码 图5-1发送邮件程序账号设置测试 5.2发送电子邮件程序测试 在上一步已经测试了账号输入,
39、然后再收件人地址输入框中输入“hubeigongpeng”,在@邮件服务器输入框中输入“”。接下来在主题输入框中输入“测试邮件,收到勿回”,正文中输入“测试邮件,收到勿回!”,然后添加附件“测试文件.doc”(如图5-2),最后点击发送,当邮件发送成功会在发送旁边返回“发送成功”的信息。 如图5-2为添加附件的界面。 图5-2发送电子邮件程序添加附件 如图5-3为测试邮件发送成功。 图5-3发送电子邮件程序主界面 5.3电子邮件程序系统托盘测试 测试最后进入系统托盘测试,点击主界面的“”按钮,然后会看到主界面在桌面上消失,在桌面左下角的任务栏里,可以找到一个类似地
40、球的图标(如图5-3),当鼠标移上去时会有字体显示“CY电邮”,然后点击鼠标邮件,出现小菜单(如图5-4),选择“主界面”会弹出主界面,并有提示(如图5-5),选择“退出程序”,程序会退出。 如图5-4所示:系统托盘的实现 图5-4电子邮件程序(cy电邮)系统托盘 如图5-5所示:系统托盘右键菜单 图5-5电子邮件程序系统托盘右键菜单 如图5-6所示:弹出主界面提示 图5-6电子邮件程序系统托盘主界面弹出提示 设计小结 在课程设计即将完成之际,我想向曾经给我帮助的陈涛老师和一起讨论的同学表示衷心的感谢。本次设计过程中遇到了很多程序上的问题,在老师不厌其烦
41、地指导和自己不断地思考中才得以解决,然后是不停地通宵研究,编译,拿出了刻苦的精神后,问题也就迎刃而解了。在这两个星期的努力中,我终于设计出一个电子邮件发送系统并调试通过,最后整理出设计报告。通过编写电子邮件的发送程序,我知道了java除了本来的许多包,还有需要特殊作用的扩展包,如本系统用到的javamail包等,目前系统还不够完整,还存在着很多的不足和不完善的地方。不过我相信随着以后学的专业知识越来越多,我会完善这个系统的。在完成过程中我在托盘程序时出现了鼠标点击的错误,在老师的帮助下我找到了错误并解决了,在发送邮件时出现无法登陆邮件服务器错误,问了老师才知道是因为我发的是QQ邮箱,而本身QQ
42、邮箱的SMTP服务器没打开,所以我该用163邮箱发送。 最后,衷心感谢在百忙之中抽出时间审阅本课程报告的陈涛老师。 参考文献 [1]谢希仁.计算机网络.第五版[M].北京:电子工业出版社,2008.1 [2]耿祥义,张跃平.Java大学实用教程.第二版[M].北京:电子工业出版社,2005.5 [3][美]Rogers Cadenhead. Java编程入门经典.梅兴文译.第4版[M].北京:人民邮电出版社,2007 [4]王勇,代桂平.计算机网络课程设计[M].北京:清华大学出版社,2009.6 [5]耿
43、祥义,张跃平.Java大学实用教程学习指导.第二版[M].北京:电子工业出版社,2005.5 附录1:SystemTrayTest类 功能:该类是实现主界面系统托盘功能的类。 import java.awt.AWTException; import java.awt.Image; import java.awt.Menu; import java.awt.MenuItem; import java.awt.PopupMenu; import
44、 java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import javax.swing.JFrame; public cl
45、ass SystemTrayTest extends JFrame implements ActionListener { private static final long serialVersionUID = 5381564219860736835L; PopupMenu popup = new PopupMenu(); MenuItem[] mItem = { new MenuItem("账号设置"),new MenuItem("退出程序") }; SystemTray tray; TrayIcon trayIcon; Image image1; Im
46、age image; boolean flag = true; MailSender inst; // public LoginDialog dlg; public SystemTrayTest() { for (int i = 0; i < mItem.length; i++) { mItem[i].addActionListener(this); } popup.add(mItem[0]); popup.add(mItem[1]); if (SystemTray.isSupported()) { tray = SystemTr
47、ay.getSystemTray(); image = Toolkit.getDefaultToolkit().getImage("imag/e_mail.png"); image1 = Toolkit.getDefaultToolkit().getImage("imag/e_mail.png"); trayIcon = new TrayIcon(image1, "CY电邮", popup); trayIcon.setImageAutoSize(true); try { tray.add(trayIcon); } catch (AWTE
48、xception e) { e.printStackTrace(); } trayIcon.addActionListener(this); trayIcon.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getSource() == trayIcon && e.getButton() == MouseEvent.BUTTON1) { if (flag) { setS
49、tate(1); flag = false; } else { setState(0); flag = true; } } setVisible(true); } }); } else{ System.out.println("您的系统不支持托盘程序。"); } inst = new MailSender(); inst.setLocationRelativeTo(null); inst.setBounds(400, 200, 420, 400); inst.setVisible(true); } public void actionPerformed(ActionEvent e) { if (e.getSource() == mItem[0]) { trayIcon.setImage(image1); inst.setVisible(true); trayIcon.displayMessage("主界面", "已经入主界面", TrayIcon.Mess






