目录
1. 原理分析
SMTP协议
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件
的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件
时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程
只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件。SMTP
是一种TCP协议支持的提供可靠且有效电子邮件传输的应用层协议。
SMTP通信过程:
- 发送端邮件服务器(以下简称客户端)与接收端邮件服务器(以下简称服务器)的25号端口建立TCP连 接。
- 客户端向服务器发送各种命令,来请求各种服务(如认证、指定发送人和接收人)。
- 服务器解析用户的命令,做出相应动作并返回给客户端一个响应。
- 2)和3)交替进行,直到所有邮件都发送完或两者的 连接被意外中断。
Smtp命令(命令不区分大小写,参数区分大小写)
Smtp常见响应
501参数格式错误 | 502命令不可实现 |
503错误的命令序列 | 504命令参数不可实现 |
211系统状态或系统帮助响应 | 214帮助信息 |
220<domain>服务就绪 | 221<domain>服务关闭 |
421<domain>服务未就绪,关闭传输信道 | 250要求的邮件操作完成 |
251用户非本地,将转发向<forward-path> | 450要求的邮件操作未完成,邮箱不可用 |
550要求的邮件操作未完成,邮箱不可用 | 451放弃要求的操作;处理过程中出错 |
551用户非本地,请尝试<forward-path> | 452系统存储不足,要求的操作未执行 |
552过量的存储分配,要求的操作未执行 | 553邮箱名不可用,要求的操作未执行 |
354开始邮件输入,以"."结束 | 554操作失败 |
2. 前端页面
在SMTP协议中,我们需要一个授权码,而不是邮箱的密码,如何开启邮箱的SMTP协议服务请查看以下文章
https://www.cnblogs.com/shangdawei/p/4305989.html
这位大神已经写好了;开启了SMTP服务后,我们就正式入手我们的项目了。我们是模拟邮箱发送,想一想业务逻辑,思路很清晰,分为
注册(注册的时候输入我们的邮箱和对应的授权码而不是邮箱的密码;授权码就是刚刚在开启SMTP协议的时候自己设置的授权码);
登录(从数据库调出数据进行判断)
发送页面
注册页面register.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Register</title>
<link rel="stylesheet" href="./css/Register.css">
<script src="./js/register.js"></script>
</head>
<body>
<form action="./RegisterDo" method="POST" onsubmit="return check()">
<div id="con">
<div style="background-color:rgba(255, 255, 255, 0);">Register</div>
<div>
<label for="username">用户名</label>
<input type="text" id="username" name="username" autocomplete="off" required>
</div>
<div>
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
</div>
<div>
<label for="ConfirmPass">确认密码</label>
<input type="password" id="ConfirmPass" name="ConfirmPass" required>
</div>
<div>
<button type="submit">注 册</button>
</div>
</div>
</form>
</body>
</html>
登录页面Login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet" href="./css/Login.css">
</head>
<body>
<div id="Hp">
<img src="http://baiducdn.pig66.com/uploadfile/2017/0511/20170511074941526.jpg" alt="头像丢失了">
</div>
<form action="./LoginDo" method="POST">
<div id="show">
<table>
<tr>
<td><input type="text" name="username" placeholder=" Username" class="inp1"></td>
</tr>
<tr>
<td><input type="password" name="password" placeholder=" Password" class="inp1"></td>
</tr>
<tr>
<td>
<span><input type="checkbox" name="" class="inp2"></span>
<span class="sp1">Remenmber Me</span>
<span class="sp2"><a href="register.html">Reqister</a></span>
</td>
</tr>
<tr>
<td>
<input type="submit" value="LOGIN" class="bt">
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
发送页面sendmail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>发送邮件</title>
<link rel="stylesheet" href="./css/sendmail.css">
<script src="./js/jquery-3.2.1.min.js"></script>
</head>
<body>
<form action="./SendDO" method="post">
<div class="box">
<div class="box20">
<span></span>
<input type="text" name="username" value=<%=request.getAttribute("username")%>>
</div>
<div class="box20">
<span></span>
<input type="text" name="password" value=<%=request.getAttribute("password")%>>
</div>
<div class="h">
<hr>
<h1>XX制作制作->欢迎<%=request.getAttribute("username")%>使用模拟邮件发送器网页版</h1>
<hr>
</div>
<div class="box1">
<span>收件人:</span>
<input type="text" name="receiverName" id="receiver" required>
</div>
<div class="box2">
<span>主 题:</span>
<input type="text" name="titlename" id="theme" required>
</div>
<div class="box3">
<span>正 文:</span>
<textarea name="infoName" id="info" cols="76" rows="10" required></textarea>
</div>
<div class="last">
<input type="submit" value="发送" id="send">
<input type="reset" value="重写" id="reset">
</div>
</div>
</form>
</body>
</html>
CSS文件:
Register.css
body{
background: url("../imge/3.jpg");
background-size: cover;
}
#con{
color: rgb(245, 243, 243);
width: 600px;
height: 280px;
margin: auto;
margin-top: 200px;
background-color: rgba(0, 0, 0, 0.4);
vertical-align:middle;
text-align: center;
border-radius: 15px;
}
#con div{
margin: auto;
width: 500px;
margin-top: 15px;
font-size: 20px;
display:inline-block;
background-color: darkorange;
}
.div{
background-color: rgba(253, 253, 253, 0);
}
#con label{
text-align: center;
width: 20%;
height: 30px;
line-height: 30px;
float: left;
}
#con input{
width: 79%;
height: 30px;
font-size: 20px;
padding: 0 0;
}
#con button{
color:white;
width: 100%;
font-size: 20px;
background-color: aqua;
}
#con button:hover{
background-color: rgb(102, 255, 0);
}
Login.css
body{
height: 100%;
margin: 0 0;
background: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1557133865275&di=ddbdf1e859e5bbc82cc91298b45a4f7c&imgtype=0&src=http%3A%2F%2Fpic164.nipic.com%2Ffile%2F20180509%2F18980004_153526848038_2.jpg);
background-size: cover;
}
#Hp{
margin-top: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
#Hp img{
width: 120px;
height: 120px;
border-radius: 50%;
margin: auto;
border:3px solid #fff;
}
#show{
width: 400px;
margin:auto;
margin-top: 50px;
font-family: '楷体';
font-size: 20px;
background:rgba(41, 31, 180, 0.30);
border-radius: 5px;
border: 1.5px solid #ffffff;
}
#show table{
margin:auto;
width: 100%;
border-spacing: 25px;
}
.inp1{
background:rgba(41, 31, 180, 0.2);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 25px;
color: rgb(255, 255, 255);
width: 100%;
border-radius: 8px;
border: 0;
}
.inp2{
width:15px;
height:15px;
}
.sp1{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #cdcedb;
}
input::-webkit-input-placeholder{
color:#cdcedb;
}
.sp2{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color:#cdcedb;
position: relative;
float: right;
margin-right: 2px;
}
.sp2 a{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color:#cdcedb;
width:20px;
height:20px;
text-decoration: none;
}
.sp2 a:hover{
color: rgb(80, 71, 202);
}
input.bt{
background-color: aqua;
width: 100%;
border-radius: 4px;
border: 0;
font-size: 25px;
color: rgb(133, 133, 133);
}
.bt:hover{
background-color: rgba(80, 71, 202, 0.774);
}
sendmail.css
body {
padding: 0;
margin: 0;
background: url(../imge/7.jpg);
background-size: cover;
}
.h{
background-color: rgb(180, 214, 246);
}
h1{
margin-left: 55px;
}
.box {
width: 1200px;
height: 710px;
margin: auto;
margin-top: 50px;
background-color: #D2E9FF;
}
.box1 {
height: 50px;
width: 100%;
margin-top: 15px;
}
.box2 {
height: 50px;
width: 100%;
}
.box3 {
height: 400px;
width: 100%;
}
.box3>textarea{
width: 1000px;
font-size: 25px;
}
.box span {
display: block;
height: 50px;
width: 80px;
float: left;
text-align: center;
line-height: 50px;
margin-left: 55px;
}
.box input {
display: block;
height: 20px;
width: 1000px;
float: left;
margin-top: 13px;
}
#info {
height: 400px;
overflow: hidden;
margin-top: 15px;
}
.last {
width: 100%;
height: 100px;
}
#send{
width: 70px;
height: 30px;
background-color: rgb(163, 147, 147);
color: rgb(255, 255, 255);
margin-top: 40px;
font-family: "楷体";
border-radius: 10px;
border:0px;
margin-left: 850px;
}
#send:hover{
background-color: rgb(212, 82, 82);
}
#reset{
width: 70px;
height: 30px;
background-color: rgb(163, 147, 147);
color: white;
margin-top: 40px;
font-family: "楷体";
border-radius: 10px;
border:0px;
margin-left: 50px;
}
#reset:hover{
background-color: rgb(212, 82, 82);
}
.box20{
display: none;
}
js文件:除了以下两个js文件还需要Jquery.js,这个在网上可以下载
register.js
function check(){
var username=document.getElementById("username");
var password=document.getElementById("password");
var regex = /^\w+@\w+.\w+\.?\w+$/;
if(!regex.test(username.value)){
alert("邮件格式错误!请检查格式!");
return false;
}
if(password.value.length<3){
alert("密码长度必须大于3个字符!");
return false;
}
var ConfirmPass=document.getElementById("ConfirmPass");
if(ConfirmPass.value!=password.value){
alert("两次输入的密码不一致!");
return false;
}
}
sendmail.js
var regex = /^\w+@\w+.\w+\.?\w+$/;
$(document).ready(function () {
$("#receiver").blur(function () {
if (!regex.test($("#receiver").val())) {
alert("邮箱格式错误!请输入正确的邮箱!");
}
});
$("#reset").click(function (){
$("#info").val("");
});
});
3. 数据库设计
数据库设计很简单,我们只需要存储用户名和对应的授权码;数据库代码如下
/*
Navicat MySQL Data Transfer
Source Server : MySQL
Source Server Version : 50617
Source Host : localhost:3306
Source Database : popmail
Target Server Type : MYSQL
Target Server Version : 50617
File Encoding : 65001
Date: 2019-05-07 22:22:15
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`username` varchar(25) NOT NULL,
`password` varchar(25) NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4. 后端数据处理
前端页面和数据库设置已经设置好了,接下来就是对前端传输的数据给后端进行处理,首先要完成注册,要将前端页面的数据存入到数据库中,基于Java的话就选择jdbc。另外要发送邮件还需要一个javax.mail.jar的jar包
连接器下载:https://dev.mysql.com/downloads/connector/j/
javax.mail.jar下载:https://mvnrepository.com/artifact/javax.mail/smtp
下载好放在项目下的WebContent的WEB-INF的lib文件夹下面。
完成以上步骤后我们就可以开始编写代码了。
为了方便我们查询数据库,先写一个jdbc工具类
JDBCTools.java
package com.mail.chtw.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCTools {
private Connection conn;
private PreparedStatement ps;
private ResultSet rs;
public JDBCTools() {
//一.加载驱动类
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//二.应用层
/**
* 1.获取连接
* @return
* @throws SQLException
*/
public Connection getConnetion() throws SQLException {
//三个参数(url,用户,密码)
conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/popmail","root","数据库密码");
return conn;
}
public ResultSet executeQuery(String sql,Object ...obj) {//...可变参数
try {
//1.产生连接
conn = getConnetion();
//2.用连接产生prepareStatement
ps = conn.prepareStatement(sql);
//3.设置所有参数
for (int i = 0; i < obj.length; i++) {
ps.setObject(i+1, obj[i]);
}
//4.执行查询,产生结果集
rs=ps.executeQuery();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rs;
}
//增删改
public int executeUpdate(String sql,Object ...obj) {
int count = 0;
try {
conn = getConnetion();
ps = conn.prepareStatement(sql);
for (int i = 0; i < obj.length; i++) {
ps.setObject(i+1, obj[i]);
}
count = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return count;
}
//关闭资源
public void close() {
try {
rs.close();
ps.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
RegisterDo.java
package com.mail.chtw.html;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mail.chtw.jdbc.JDBCTools;
@WebServlet("/RegisterDo")
public class RegisterDo extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username =request.getParameter("username");
String password = request.getParameter("password");
JDBCTools tools = new JDBCTools();
response.setContentType("text/html;charset=UTF-8");
String sql = "select * from user where username=?";
String sql1 = "insert into user value(?,?)";
ResultSet rs = tools.executeQuery(sql,username);
try {
if(rs.next()) {
response.getWriter().print("<script>alert('注册失败!该账号已被注册!请重试!');location='register.html';</script>");
}else {
tools.executeUpdate(sql1, username,password);
response.getWriter().print("<script>alert('注册成功!请登录!');location='Login.html';</script>");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
LoginDo.java
package com.mail.chtw.html;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mail.chtw.jdbc.JDBCTools;
@WebServlet("/LoginDo")
public class LoginDo extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginDo() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username =request.getParameter("username");
String password = request.getParameter("password");
JDBCTools tools = new JDBCTools();
response.setContentType("text/html;charset=UTF-8");
String sql = "select password from user where username=? and password=?";
ResultSet rs = tools.executeQuery(sql,username,password);
try {
if(rs.next()) {
request.setAttribute("username",username);
request.setAttribute("password", password);
request.getRequestDispatcher("./SendMail.jsp").forward(request, response);
}
else {
response.getWriter().print("<script>alert('登录失败!账号或密码错误!请重试!');location='Login.html';</script>");
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
SendDO.java
package com.mail.chtw.html;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/SendDO")
public class SendDO extends HttpServlet {
private static final long serialVersionUID = 1L;
public SendDO() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String myemail = request.getParameter("username");
String p = request.getParameter("password");
String re = request.getParameter("receiverName");
String title =new String(request.getParameter("titlename").getBytes("ISO8859-1"),"UTF-8");
String body =new String(request.getParameter("infoName").getBytes("ISO8859-1"),"UTF-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
try {
connect(myemail,p,title,re,body);
request.setAttribute("username",myemail);
request.setAttribute("password", p);
request.getRequestDispatcher("./SendMail.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public static MimeMessage createMimeMessage(Session session, String sendMail,String title,String receiveMail,String body) throws Exception {
// 1. 创建邮件
MimeMessage message = new MimeMessage(session);
// 2. 发件人
message.setFrom(new InternetAddress(sendMail));
// 3. 收件人(可以增加多个收件人、抄送、密送)
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(receiveMail));
// 4. 邮件主题
message.setSubject(title);
// 5. 邮件正文
message.setContent(body, "text/html;charset=UTF-8");
// 6. 设置发件时间
message.setSentDate(new Date());
// 7. 保存设置
message.saveChanges();
return message;
}
public void connect(String myemail,String p,String title,String re,String body) throws Exception {
String myEmailAccount = myemail;
String myEmailPassword = p;
// 发件人邮箱的 SMTP 服务器地址
String myEmailSMTPHost = "smtp.163.com";
// 收件人邮箱(替换为自己知道的有效邮箱)
String receiveMailAccount = re;
Properties props = new Properties(); // 参数配置
props.setProperty("mail.transport.protocol", "smtp"); // 使用的协议
props.setProperty("mail.smtp.host", myEmailSMTPHost); // 发件人的邮箱的 SMTP 服务器地址
props.setProperty("mail.smtp.auth", "true"); // 需要请求认证
// 2. 根据配置创建会话对象, 用于和邮件服务器交互
Session session = Session.getInstance(props);
// 设置为debug模式, 可以查看详细的发送 log
session.setDebug(true);
// 3. 创建一封邮件
MimeMessage message = createMimeMessage(session, myEmailAccount, title,receiveMailAccount,body);
// 4. 根据 Session 获取邮件传输对象
Transport transport = session.getTransport();
// 5. 使用 邮箱账号 和 密码 连接邮件服务器, 这里认证的邮箱必须与 message 中的发件人邮箱一致, 否则报错
transport.connect(myEmailAccount, myEmailPassword);
// 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
transport.sendMessage(message, message.getAllRecipients());
// 7. 关闭连接
transport.close();
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>POPmail</display-name>
<welcome-file-list>
<welcome-file>Login.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>RegisterDo</servlet-name>
<servlet-class>com.mail.chtw.html.RegisterDo</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginDo</servlet-name>
<servlet-class>com.mail.chtw.html.LoginDo</servlet-class>
</servlet>
<servlet>
<servlet-name>SendDo</servlet-name>
<servlet-class>com.mail.chtw.html.SendDo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterDo</servlet-name>
<url-pattern>/reg/</url-pattern>
</servlet-mapping>
</web-app>
5. 参考文献
SMTP协议:https://blog.csdn.net/qq_35644234/article/details/68961603
数据库安装配置:https://blog.csdn.net/chen_hao_181/article/details/83861507
邮箱开启SMTP服务:https://www.cnblogs.com/shangdawei/p/4305989.html
6. 注意事项
上面文件中所有以数字命名的图片都需要自己找,并放在指定的文件夹中。这种做法有一个小缺点,就是邮件发送成功后没有提示,但是我们可以从eclipse控制台中看出来发送成功了。
本网站只实现了163邮箱的发送。
欢迎关注熊熊出没ING公众号,不定时跟新Java、python、信息安全等相关知识哦。