feat: add email client

This commit is contained in:
Sandro Eiler 2024-02-26 22:00:33 +01:00
parent 13db7853bd
commit ac216925ff
7 changed files with 167 additions and 4 deletions

View file

@ -21,6 +21,7 @@ pub struct Settings {
pub struct EmailClientSettings {
pub base_url: String,
pub sender_email: String,
pub authorization_token: Secret<String>,
}
impl EmailClientSettings {

View file

@ -1,19 +1,26 @@
use crate::domain::SubscriberEmail;
use reqwest::Client;
use secrecy::{ExposeSecret, Secret};
#[derive(Clone)]
pub struct EmailClient {
http_client: Client,
base_url: String,
sender: SubscriberEmail,
authorization_token: Secret<String>,
}
impl EmailClient {
pub fn new(base_url: String, sender: SubscriberEmail) -> Self {
pub fn new(
base_url: String,
sender: SubscriberEmail,
authorization_token: Secret<String>,
) -> Self {
Self {
http_client: Client::new(),
base_url,
sender,
authorization_token,
}
}
@ -24,6 +31,69 @@ impl EmailClient {
html_content: &str,
text_content: &str,
) -> Result<(), String> {
todo!()
// TODO: use `reqwest::Url::join` and change `base_url`'s type from `String` to `reqwest::Url`
let url = format!("{}/email", self.base_url);
let request_body = SendEmailRequest {
from: self.sender.as_ref().to_owned(),
to: recipient.as_ref().to_owned(),
subject: subject.to_owned(),
html_body: html_content.to_owned(),
text_body: text_content.to_owned(),
};
let builder = self
.http_client
.post(&url)
.header(
"X-Postmark-Server-Token",
self.authorization_token.expose_secret(),
)
.json(&request_body);
Ok(())
}
}
#[derive(serde::Serialize)]
struct SendEmailRequest {
from: String,
to: String,
subject: String,
html_body: String,
text_body: String,
}
#[cfg(test)]
mod tests {
use crate::domain::SubscriberEmail;
use crate::email_client::EmailClient;
use fake::faker::internet::en::SafeEmail;
use fake::faker::lorem::en::{Paragraph, Sentence};
use fake::{Fake, Faker};
use secrecy::Secret;
use wiremock::matchers::any;
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn send_email_fires_a_request_to_base_url() {
// Arrange
let mock_server = MockServer::start().await;
let sender = SubscriberEmail::parse(SafeEmail().fake()).unwrap();
let email_client = EmailClient::new(mock_server.uri(), sender, Secret::new(Faker.fake()));
Mock::given(any())
.respond_with(ResponseTemplate::new(200))
.expect(1)
.mount(&mock_server)
.await;
let subscriber_email = SubscriberEmail::parse(SafeEmail().fake()).unwrap();
let subject: String = Sentence(1..2).fake();
let content: String = Paragraph(1..10).fake();
// Act
let _ = email_client
.send_email(subscriber_email, &subject, &content, &content)
.await;
// Assert
}
}

View file

@ -25,7 +25,11 @@ async fn main() {
.email_client
.sender()
.expect("Invalid sender email address.");
let email_client = EmailClient::new(configuration.email_client.base_url, sender_email);
let email_client = EmailClient::new(
configuration.email_client.base_url,
sender_email,
configuration.email_client.authorization_token,
);
startup::run(listener, connection_pool, email_client)
.await
.unwrap();