内容介绍
本专题将带你使用逐步实现一个非常常见的功能:在用户注册时,通过发送验证码。RabbitMQ 消息队列
RabbitMQ 是目前市场上最流行的消息队列之一,本章将讨论如何安装部署 RabbitMQ。通过 lapin 集成 RabbitMQ
`lapin` 是一个用 rust 实现的 AMQP 客户端,它可以实现与 RabbitMQ 的交互。通过 lettre 发送邮件
本章将讨论使用 `lettre` 在 rust 中实现发送邮件。我们将分别使用 Gmail 和 Mail.ee 来作测试。实现用户注册与激活
本章将实现最终的功能:用户注册,并发送激活邮件。
通过 lettre 发送邮件
本章将讨论使用 lettre
在 rust 中实现发送邮件。我们将分别使用 Gmail 和 Mail.ee 来作测试。
Gmail 的设置
- 开启了两步验证
- 创建了应用专用密码
详细操作,请查看官方文档。
Mail.ee 的设置
和 Gmail 相比,Mail.ee 的操作就简单多了。注册并登录 Mail.ee,然后:
- 点击右上角展开菜单按钮
- 点击
EMAIL OPTIONS
- 点击
Outlook, email programs
- 点击
Enable
- 最终显示了专用密码以及 IMAP/SMTP 的连接地址和端口
依赖
[dependencies]
# ...
lettre = {version="0.10",features=["tokio1-native-tls"]}
配置
示例一:Gmail配置
EMAIL.USERNAME='[email protected]'
EMAIL.PASSWORD='<你的专用密码>'
EMAIL.HOST='smtp.gmail.com'
示例二:Mail.ee配置
EMAIL.USERNAME='[email protected]'
EMAIL.PASSWORD='<你的专用密码>'
EMAIL.HOST='mail.mail.ee'
模型
我们定义了一个模型,用于映射每一封邮件:
pub struct Email {
pub from: String, // 发件人地址。通常和配置中的username一样
pub to: String, // 收件人地址
pub subject: String, // 邮件主题
pub body: String, // 邮件内容
}
impl Email {
/// 转换为 letter 的 Message 类型
pub fn to_message(&self) -> Result<Message> {
Message::builder()
.from(self.from.as_str().parse().unwrap())
.to(self.to.as_str().parse().unwrap())
.subject(self.subject.as_str())
.header(ContentType::TEXT_PLAIN) // 如要发送 HTML 邮件,将这个换成 ContentType::TEXT_HTML
.body(self.body.clone())
.map_err(Error::from)
}
}
/// 同步发送
pub fn sync_send(cfg: &EmailConfig, m: &model::email::Email) -> Result<Response> {
let message = m.to_message()?;
let creds = Credentials::new(cfg.username.clone(), cfg.password.clone());
let mailer = SmtpTransport::relay(&cfg.host)
.map_err(Error::from)?
.credentials(creds)
.build();
mailer.send(&message).map_err(Error::from)
}
- 生成一个邮件内容:
let message = m.to_message()?;
- 生成身份验证信息:
let creds = Credentials::new(用户名, 密码);
- 连接服务器:
SmtpTransport::relay()
- 发送邮件:
mailer.send(&message)
测试
#[test]
fn test_sync_send_email() {
let cfg = get_cfg().unwrap();
let m = model::email::Email {
from: format!("{}", &cfg.username),
to: format!("[email protected]"),
subject: format!("试试同步发送"),
body: format!("你好呀,这是用lettre同步发送的邮件!"),
};
let resp = super::sync_send(&cfg, &m).unwrap();
tracing::info!("{:?}", resp);
}
/// 异步发送
pub async fn send(cfg: &EmailConfig, m: &model::email::Email) -> Result<Response> {
let message = m.to_message()?;
let creds = Credentials::new(cfg.username.clone(), cfg.password.clone());
let mailer = AsyncSmtpTransport::<Tokio1Executor>::relay(&cfg.host)
.map_err(Error::from)?
.credentials(creds)
.build();
mailer.send(message).await.map_err(Error::from)
}
和同步发送大同小异:
测试
#[tokio::test]
async fn test_async_send_email() {
let cfg = get_cfg().unwrap();
let m = model::email::Email {
from: format!("{}", &cfg.username),
to: format!("[email protected]"),
subject: format!("试试异步发送"),
body: format!("你好呀,这是用lettre异步发送的邮件!"),
};
let resp = super::send(&cfg, &m).await.unwrap();
tracing::info!("{:?}", resp);
}
本章代码位于02/lettre分支。