Hi~ 这里是华南理工大学软件开发实训作品:邮件系统——云信邮件系统。云信Mail提供了全面、便捷的功能和简洁、美观的用户界面,用户可以方便地查看邮件、发送邮件、管理邮件。云信Mail支持注册邮箱、接收邮件、发送邮件、标记已读/未读邮件、删除邮件、星标邮件、草稿箱、新邮件到达通知、搜索、过滤邮件等功能,用户可以在云信Mail上高效地处理邮件。更多内容请查阅项目Feature。
前端使用 Vue3 + vue-cli
框架和 element-plus
组件库 ,后端使用 Springboot
框架,数据库使用 MySQL
远程数据库和 mybaits
, 云服务器和短信服务都使用 阿里云
的产品,AI服务使用 智谱清言
的接口。
- 🔥邮件和附件分离、均采用云端存储:支持使用阿里云服务器和对象存储服务分别存储附件和数据库。
- 邮箱注册:云信Mail提供注册功能,用户可以用手机号注册邮箱,经过短信验证码验证,获得专属邮箱地址后缀
"@yunxin.com"
。服务器保存用户信息到数据库中,用于用户登录邮箱时验证。 - 接收邮件:一旦用户登录了电子邮件账户,云信Mail基于HTTP协议,可以自动连接到邮件服务器并下载新邮件,一旦新邮件被下载,用户可以在收件箱中查看。
- 发送邮件:通过HTTP协议与邮件服务器进行通信以发送邮件,用户需要在表单中提供收件人地址、抄送、主题、邮件内容、上传的附件(可选)。
- 🔥AI支持:目前用户可以在阅读邮件的时候让AI自动总结邮件内容,方便用户快速了解邮件内容,并且具有良好的可拓展性,可接入更多丰富的AI服务和个性化配置,如自选大模型接口、微调训练专用agent、实现垃圾邮件检测和翻译等。
- 🔥标记已读/未读邮件:用户可以标记邮件为已读或未读,该状态会同步到服务器,在用户下次登录或者在其他设备登录时保持一致。
- 删除邮件:用户可以选中批量删除邮件,将邮件移动到垃圾箱,可以进一步删除垃圾箱中的邮件,邮件会被永久删除。
- 星标邮件:用户可以将重要的邮件标记为星标邮件,方便查找。
- 批量管理邮件 支持多选操作一键应用到所有邮件
- 草稿箱:用户可以保存未发送的邮件到草稿箱,下次登录时可以继续编辑。同样是存储在了后端,保证用户在不同设备上登录时草稿箱内容一致。
- 🔥新邮件到达通知:当用户收到新邮件时,云信Mail会弹出通知,提醒用户查看新邮件,并更新邮件列表。
- 支持搜索、过滤邮件:用户可以通过关键字搜索邮件,也可以通过发件人、收件人、主题、时间等条件过滤邮件。
- 客户端和服务端邮件同步:用户在不同设备上登录时,邮件状态、邮件内容、附件等信息都会同步到用户的设备上。
- 用户友好的UI界面:云信Mail提供了简洁、美观的用户界面,用户可以方便地查看邮件、发送邮件、管理邮件。
- 对RESTFUL接口响应的成功/错误弹窗:用户在操作时,会有相应的提示,方便用户了解操作结果,提升用户体验。例如成功或者失败(验证失败、操作不合法等)
- 服务端使用数据库对邮件进行存储:邮件的元数据和正文,包括附件的元数据,都会存储在数据库中,保证数据的安全性和一致性。
- 使用MIME发送附件,收件人能下载对应邮件中的附件
- 🔥客户端本地缓存:断网时,用户的操作会被缓存,网络恢复后会自动执行
- 合理的报文约定:前后端交互的报文格式合理,包括请求报文和响应报文,保证数据的完整性和一致性
- 服务端数据库设计合理:根据E-R图设计数据库,将数据放在多个表中,保证数据的一致性和完整性
层次 | 内容和功能 |
---|---|
数据层(Data Layer) | Mapper接口和映射文件 |
服务层(Service Layer) | 服务接口和实现类 |
控制层(Controller Layer) | Controller类 |
工具类和帮助类(Utility Classes) | 工具类和帮助类 |
实体类(Entities) | Java实体类 |
配置类(Configuration Classes) | 配置类 |
数据传输对象(DTOs) | 用于服务层与控制层的数据交换 |
视图对象(VOs) | 用于封装展示给用户的数据 |
邮件模块(Mail Module) | 邮件处理接口和实现 |
身份验证与权限控制(Authentication & Authorization) | 安全配置 |
API 文档生成(API Documentation) | Swagger |
AI 服务(AI Service) | AI服务接口和实现 |
其他(Miscellaneous) | 过滤器、DTO、枚举等 |
- 邮件分类:用户可以将邮件分类,例如工作、学习、生活等,方便用户查找邮件。
- 邮件标签:用户可以给邮件打标签,例如重要、紧急、待办等,方便用户查找邮件。
- 邮件过滤规则:用户可以设置邮件过滤规则,例如将某个发件人的邮件自动归类到某个文件夹。
- 邮件定时发送:用户可以设置邮件定时发送,例如设置明天早上8点发送邮件。
- 邮件加密:用户可以对邮件进行加密,只有指定的接收者才能解密查看邮件。
- 邮件签名:用户可以设置邮件签名,例如姓名、职务、公司等信息。
- 邮件模板:用户可以设置邮件模板,例如常用的请假、报销、感谢等邮件模板。
- 邮件统计:用户可以查看邮件统计数据,例如收发邮件数量、邮件时长、邮件分类等。
- 邮件备份:用户可以备份邮件到本地或者云端,保证邮件数据的安全性。
- 邮件回复:用户可以回复邮件,可以选择是否附带原邮件内容。
在本地部署本项目,需要分别安装服务端和客户端的依赖,分别进入 backend
和 frontend
目录,使用 npm
或者 yarn
执行依赖自动安装命令:
项目前后端分离,在Mail仓库下的frontend是作为子模块存在,实际上指向的是Mail-frontend仓库。你也可以到 Mail-frontend 获取单独的前端代码。
cd Mail/[backend/frontend]
npm install
或者
cd Mail/[backend/frontend]
yarn install
在本地部署或者开发本项目,需要分别启动服务端和客户端,分别进入 backend
和 frontend
目录,执行启动命令:
cd Mail/[backend/frontend]
npm run serve
cd Mail/[backend/frontend]
npm run build
将打包后的前端静态资源和后端文件部署到服务器上,推荐使用pm2
启动后端服务。
支持在线查看接口文档:在线接口文档
绘制并根据E-R图将数据放在多个表中 服务器将邮件正文和附件进行分离存储(将邮件本体存储数据库中,附件存储在磁盘)
字段 | 类型 | 约束 | 说明 |
---|---|---|---|
id | integer | primary key | 用户id |
username | varchar(255) | not null | 用户名 |
password | varchar(255) | not null | 密码 |
emailAddress | varchar(255) | not null | 邮箱地址 |
telephone | varchar(255) | not null | 电话号码 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | not null | 更新时间 |
字段 | 类型 | 约束 | 说明 |
---|---|---|---|
id | integer | primary key | 邮件id |
sender_id | integer | not null | 发送者id |
receiver_id | integer | not null | 接收者id |
owner_id | integer | not null | 邮件所有者id |
theme | varchar(255) | not null | 邮件主题 |
content | text | not null | 邮件内容 |
send_time | varchar(255) | not null | 发送时间 |
star | integer | not null | 星标 |
readis | integer | not null | 已读 |
draft | integer | not null | 草稿 |
junk | integer | not null | 是否废弃 |
cc | text | - | 抄送的邮件地址列表 |
字段 | 类型 | 约束 | 说明 |
---|---|---|---|
id | integer | not null | 邮件id |
file_name | varchar(255) | not null | 附件文件名 |
file_size | bigint | not null | 文件大小 |
download——url | varchar(255) | not null | 下载链接 |
create_time | datetime | not null | 创建时间 |
Base URLs:
POST /mail/send
Body 请求参数
multipleFiles: string
senderId: "7"
targetEmailAddress: [email protected]
theme: 测试
content: 你好
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
body | body | object | 否 | none |
» multipleFiles | body | string(binary) | 否 | 附件 |
» senderId | body | integer | 否 | 发送者id |
» targetEmailAddress | body | string | 否 | 目标邮箱 |
» theme | body | string | 否 | 主题 |
» content | body | string | 否 | 正文 |
返回示例
200 Response
{
"code": 0,
"message": "string",
"data": {}
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | OK | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» code | integer(int32) | false | none | 响应码,0失败1成功 | |
» message | string | false | none | 响应码为0时会携带错误消息,前端将其用显示在页面上 | |
» data | object | false | none | 响应码为1且执行查询数据操作时data会携带响应数据 |
POST /mail/view
Body 请求参数
"{\r\n \"type\": 1, // 或者 2,取决于你是想按发送者还是接收者查询\r\n \"userId\": 7,\r\n \"pageNumber\": 1, // 页码\r\n \"pageSize\": 10 ,// 每页显示的记录数\r\n \"star\": null,\r\n \"readis\": null,\r\n \"draft\": 0,\r\n \"junk\": 0,\r\n}"
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
body | body | object | 否 | none |
» userId | body | integer | 是 | 当前登录用户id |
» type | body | integer | 是 | 1我发送的 2我收到的 |
» star | body | integer | 是 | 0非星标1星标 |
» read | body | integer | 是 | 0未读1已读 |
» theme | body | string | 是 | 按邮件主题模糊查询 |
» pageNumber | body | integer | 是 | 页号 |
» pageSize | body | integer | 是 | 页大小 |
返回示例
200 Response
{
"code": 0,
"message": "string",
"data": {
"total": 0,
"records": [
{
"id": 0,
"senderUsername": "string",
"receiverUsername": "string",
"theme": "string",
"sendTime": "string",
"star": 0,
"read": 0
}
]
}
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» code | integer | true | none | none | |
» message | string | false | none | none | |
» data | object | false | none | none | |
»» total | integer | false | none | 邮件总数 | |
»» records | [object] | false | none | 邮件数组 | |
»»» id | integer | true | none | 邮件id | |
»»» senderUsername | string | true | none | 发送者用户名 | |
»»» receiverUsername | string | true | none | 接收者用户名 | |
»»» theme | string | true | none | 邮件主题 | |
»»» sendTime | string | true | none | 发送时间 | |
»»» star | integer | true | none | 0非星标1星标 | |
»»» read | integer | true | none | 0未读1已读 |
GET /mail/maildetails/{mailId}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
mailId | path | string | 是 | none |
返回示例
成功
{
"status": "success",
"data": {
"mailId": "邮件的唯一标识符",
"senderId": "发件人信息",
"receiverId": "收件人信息",
"cc": [
"抄送人列表"
],
"bcc": [
"密送人列表"
],
"subject": "邮件主题",
"content": "邮件文本内容",
"sendTime": "发送时间",
"attachments": [
{
"attachmentId": "附件的唯一标识符",
"fileName": "附件文件名",
"size": "附件大小",
"downloadUrl": "附件下载链接"
}
]
},
"message": "获取邮件详情成功",
"type": "string"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | string |
DELETE /mail/delete
Body 请求参数
{}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
ids | query | array[string] | 否 | 邮件id列表 |
body | body | object | 否 | none |
返回示例
200 Response
{
"code": 0,
"message": "string",
"data": {}
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» code | integer | true | none | 0失败1成功 | |
» message | string | true | none | none | |
» data | object | true | none | none |
PUT /mail/star
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
ids | query | array[string] | 否 | none |
返回示例
200 Response
{
"code": 0,
"message": "string",
"data": {}
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» code | integer | true | none | none | |
» message | string | true | none | none | |
» data | object | true | none | none |
PUT /mail/cancelstar
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
ids | query | array[string] | 否 | none |
返回示例
200 Response
{
"code": 0,
"message": "string",
"data": {}
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» code | integer | true | none | none | |
» message | string | true | none | none | |
» data | object | true | none | none |
PUT /mail/read/{mailId}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
mailId | path | string | 是 | none |
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
POST /user/register
Body 请求参数
{
"username": "val213",
"password": "123456",
"telephone": "1008610001"
}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
verifycode | query | string | 否 | none |
body | body | object | 否 | none |
返回示例
200 Response
{
"emailAddress": "string"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» emailAddress | string | true | none | 根据用户名创建邮箱地址返回给用户 |
POST /user/login
Body 请求参数
{
"emailAddress": "[email protected]",
"password": "123456"
}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
body | body | object | 否 | none |
返回示例
200 Response
{
"token": "string"
}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» token | string | true | none | none |
POST /user/sendverifycode
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
telephone | query | string | 否 | none |
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
POST /user/logout
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
POST /user/changepswd
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
POST /user/edit
Body 请求参数
{
"userEmail": "",
"newUserName": ""
}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
body | body | object | 否 | none |
» userEmail | body | string | 是 | none |
» newUserName | body | string | 是 | none |
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
POST /attach/upload
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
GET /attach/download/{attachmentId}
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
attachmentId | path | integer | 是 | none |
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
DELETE /attach/delete
返回示例
200 Response
{}
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
POST /ai/summarize
Body 请求参数
"{\r\n \"content\":\r\n}"
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
body | body | object | 否 | none |
返回示例
200 Response
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
{
"code": 0,
"message": "string",
"data": {}
}
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
code | integer(int32) | false | none | 响应码,0失败1成功 | none |
message | string | false | none | 响应码为0时会携带错误消息,前端将其用显示在页面上 | none |
data | object | false | none | 响应码为1且执行查询数据操作时data会携带响应数据 | none |
{
"senderId": 0,
"receiverId": 0,
"theme": "string",
"content": "string",
"multipartFile": "string"
}
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
senderId | integer(int32) | false | none | none | |
receiverId | integer(int32) | false | none | none | |
theme | string | false | none | none | |
content | string | false | none | none | |
multipartFile | string(binary) | false | none | none |