You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
WIP: email sending crate
This commit is contained in:
18
crates/email/Cargo.toml
Normal file
18
crates/email/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "mas-email"
|
||||
version = "0.1.0"
|
||||
authors = ["Quentin Gliech <quenting@element.io>"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.15.0", features = ["macros"] }
|
||||
|
||||
mas-templates = { path = "../templates" }
|
||||
anyhow = "1.0.52"
|
||||
async-trait = "0.1.52"
|
||||
|
||||
[dependencies.lettre]
|
||||
version = "0.10.0-rc.4"
|
||||
default-features = false
|
||||
features = ["tokio1-rustls-tls", "hostname", "builder", "tracing", "pool"]
|
78
crates/email/src/lib.rs
Normal file
78
crates/email/src/lib.rs
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use lettre::{
|
||||
message::{Mailbox, MessageBuilder, MultiPart},
|
||||
AsyncTransport, Message,
|
||||
};
|
||||
use mas_templates::{EmailVerificationContext, Templates};
|
||||
|
||||
pub struct Mailer {
|
||||
templates: Templates,
|
||||
from: Mailbox,
|
||||
reply_to: Mailbox,
|
||||
}
|
||||
|
||||
impl Mailer {
|
||||
pub fn new<T>(templates: &Templates, from: Mailbox, reply_to: Mailbox) -> Self {
|
||||
Self {
|
||||
templates: templates.clone(),
|
||||
from,
|
||||
reply_to,
|
||||
}
|
||||
}
|
||||
|
||||
fn base_message(&self) -> MessageBuilder {
|
||||
Message::builder()
|
||||
.from(self.from.clone())
|
||||
.reply_to(self.reply_to.clone())
|
||||
}
|
||||
|
||||
async fn prepare_verification_email(
|
||||
&self,
|
||||
to: Mailbox,
|
||||
context: &EmailVerificationContext,
|
||||
) -> anyhow::Result<Message> {
|
||||
let plain = self
|
||||
.templates
|
||||
.render_email_verification_txt(context)
|
||||
.await?;
|
||||
|
||||
let html = self
|
||||
.templates
|
||||
.render_email_verification_html(context)
|
||||
.await?;
|
||||
|
||||
let multipart = MultiPart::alternative_plain_html(plain, html);
|
||||
|
||||
let message = self.base_message().to(to).multipart(multipart)?;
|
||||
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
pub async fn send_verification_email<T>(
|
||||
&self,
|
||||
transport: &T,
|
||||
to: Mailbox,
|
||||
context: &EmailVerificationContext,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
T: AsyncTransport + Send + Sync,
|
||||
T::Error: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
let message = self.prepare_verification_email(to, context).await?;
|
||||
transport.send(message).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
#![allow(clippy::trait_duplication_in_bounds)]
|
||||
|
||||
use mas_data_model::{
|
||||
errors::ErroredForm, AuthorizationGrant, BrowserSession, StorageBackend, UserEmail,
|
||||
errors::ErroredForm, AuthorizationGrant, BrowserSession, StorageBackend, User, UserEmail,
|
||||
};
|
||||
use oauth2_types::errors::OAuth2Error;
|
||||
use serde::{ser::SerializeStruct, Serialize};
|
||||
@ -76,6 +76,15 @@ pub trait TemplateContext: Serialize {
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl TemplateContext for () {
|
||||
fn sample() -> Vec<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Context with a CSRF token in it
|
||||
#[derive(Serialize)]
|
||||
pub struct WithCsrf<T> {
|
||||
@ -440,6 +449,40 @@ impl<T: StorageBackend> TemplateContext for AccountEmailsContext<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Context used by the `emails/verification.{txt,html}` templates
|
||||
#[derive(Serialize)]
|
||||
pub struct EmailVerificationContext {
|
||||
user: User<()>,
|
||||
verification_link: Url,
|
||||
}
|
||||
|
||||
impl EmailVerificationContext {
|
||||
#[must_use]
|
||||
pub fn new(user: User<()>, verification_link: Url) -> Self {
|
||||
Self {
|
||||
user,
|
||||
verification_link,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateContext for EmailVerificationContext {
|
||||
fn sample() -> Vec<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
User::samples()
|
||||
.into_iter()
|
||||
.map(|u| {
|
||||
Self::new(
|
||||
u,
|
||||
Url::parse("https://example.com/emails/verify?code=2134").unwrap(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Context used by the `form_post.html` template
|
||||
#[derive(Serialize)]
|
||||
pub struct FormPostContext<T> {
|
||||
|
@ -48,10 +48,10 @@ mod functions;
|
||||
mod macros;
|
||||
|
||||
pub use self::context::{
|
||||
AccountContext, AccountEmailsContext, EmptyContext, ErrorContext, FormPostContext,
|
||||
IndexContext, LoginContext, LoginFormField, PostAuthContext, ReauthContext, ReauthFormField,
|
||||
RegisterContext, RegisterFormField, TemplateContext, WithCsrf, WithOptionalSession,
|
||||
WithSession,
|
||||
AccountContext, AccountEmailsContext, EmailVerificationContext, EmptyContext, ErrorContext,
|
||||
FormPostContext, IndexContext, LoginContext, LoginFormField, PostAuthContext, ReauthContext,
|
||||
ReauthFormField, RegisterContext, RegisterFormField, TemplateContext, WithCsrf,
|
||||
WithOptionalSession, WithSession,
|
||||
};
|
||||
|
||||
/// Wrapper around [`tera::Tera`] helping rendering the various templates
|
||||
@ -312,6 +312,12 @@ register_templates! {
|
||||
|
||||
/// Render the HTML error page
|
||||
pub fn render_error(ErrorContext) { "pages/error.html" }
|
||||
|
||||
/// Render the email verification email (plain text variant)
|
||||
pub fn render_email_verification_txt(EmailVerificationContext) { "emails/verification.txt" }
|
||||
|
||||
/// Render the email verification email (plain text variant)
|
||||
pub fn render_email_verification_html(EmailVerificationContext) { "emails/verification.html" }
|
||||
}
|
||||
|
||||
impl Templates {
|
||||
@ -323,9 +329,12 @@ impl Templates {
|
||||
check::render_index(self).await?;
|
||||
check::render_account_index(self).await?;
|
||||
check::render_account_password(self).await?;
|
||||
check::render_account_emails::<()>(self).await?;
|
||||
check::render_reauth(self).await?;
|
||||
check::render_form_post::<EmptyContext>(self).await?;
|
||||
check::render_error(self).await?;
|
||||
check::render_email_verification_txt(self).await?;
|
||||
check::render_email_verification_html(self).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
23
crates/templates/src/res/emails/verification.html
Normal file
23
crates/templates/src/res/emails/verification.html
Normal file
@ -0,0 +1,23 @@
|
||||
{#
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
#}
|
||||
|
||||
Hi <b>{{ user.username }}</b>,<br />
|
||||
<br />
|
||||
click this link to verify your account:<br />
|
||||
<br />
|
||||
<a href="{{ verification_link }}">{{ verification_link }}</a><br />
|
||||
<br />
|
||||
kthxbye
|
23
crates/templates/src/res/emails/verification.txt
Normal file
23
crates/templates/src/res/emails/verification.txt
Normal file
@ -0,0 +1,23 @@
|
||||
{#
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
#}
|
||||
|
||||
Hi {{ user.username }},
|
||||
|
||||
click this link to verify your account:
|
||||
|
||||
<{{ verification_link }}>
|
||||
|
||||
kthxbye
|
Reference in New Issue
Block a user