feat: replace maildev with mailpit #64
3 changed files with 88 additions and 28 deletions
|
@ -69,18 +69,22 @@ steps:
|
||||||
# secrets: [RELEASE_BOT_GPG_SIGNING_KEY, DUMBSERVE_PASSWORD, GPG_PASSWORD]
|
# secrets: [RELEASE_BOT_GPG_SIGNING_KEY, DUMBSERVE_PASSWORD, GPG_PASSWORD]
|
||||||
#
|
#
|
||||||
services:
|
services:
|
||||||
|
email:
|
||||||
|
image: axllent/mailpit
|
||||||
|
environment:
|
||||||
|
- MP_SMTP_AUTH=admin:password
|
||||||
|
- MP_MAX_MESSAGES=5000
|
||||||
|
- MP_SMTP_AUTH_ALLOW_INSECURE=1
|
||||||
|
- MP_SMTP_BIND_ADDR=0.0.0.0:10025
|
||||||
|
- MP_SMTP_AUTH_ALLOW_INSECURE=true
|
||||||
|
- MP_UI_BIND_ADDR=0.0.0.0:1080
|
||||||
|
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: postgres
|
image: postgres
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_PASSWORD=password
|
- POSTGRES_PASSWORD=password
|
||||||
|
|
||||||
email:
|
|
||||||
image: maildev/maildev:latest
|
|
||||||
environment:
|
|
||||||
- MAILDEV_SMTP_PORT=10025
|
|
||||||
- MAILDEV_INCOMING_USER=admin
|
|
||||||
- MAILDEV_INCOMING_PASS=password
|
|
||||||
|
|
||||||
meilisearch:
|
meilisearch:
|
||||||
image: getmeili/meilisearch:v1.9
|
image: getmeili/meilisearch:v1.9
|
||||||
environment:
|
environment:
|
||||||
|
|
|
@ -2,14 +2,17 @@ version: "3"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
email:
|
email:
|
||||||
image: maildev/maildev:latest
|
image: axllent/mailpit
|
||||||
restart: always
|
ports:
|
||||||
container_name: vanigam-dash-maildev
|
- 1080:1080
|
||||||
network_mode: host
|
- 10025:10025
|
||||||
environment:
|
environment:
|
||||||
- MAILDEV_SMTP_PORT=10025
|
- MP_SMTP_AUTH=admin:password
|
||||||
- MAILDEV_INCOMING_USER=admin
|
- MP_MAX_MESSAGES=5000
|
||||||
- MAILDEV_INCOMING_PASS=password
|
- MP_SMTP_AUTH_ALLOW_INSECURE=1
|
||||||
|
- MP_SMTP_BIND_ADDR=0.0.0.0:10025
|
||||||
|
- MP_SMTP_AUTH_ALLOW_INSECURE=true
|
||||||
|
- MP_UI_BIND_ADDR=0.0.0.0:1080
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16.3
|
image: postgres:16.3
|
||||||
|
|
|
@ -15,6 +15,7 @@ impl AccountValidationLinkOutMailerPort for LettreMailer {
|
||||||
first_name: &str,
|
first_name: &str,
|
||||||
validation_secret: &str,
|
validation_secret: &str,
|
||||||
) -> OutMailerPortResult<()> {
|
) -> OutMailerPortResult<()> {
|
||||||
|
// TODO: generate link from validation secret
|
||||||
let email = Message::builder()
|
let email = Message::builder()
|
||||||
.from(self.from.parse().unwrap())
|
.from(self.from.parse().unwrap())
|
||||||
.reply_to(self.reply_to.parse().unwrap())
|
.reply_to(self.reply_to.parse().unwrap())
|
||||||
|
@ -40,21 +41,63 @@ mod tests {
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
//#[derive(Deserialize, Clone)]
|
||||||
|
//struct MaildevAddress {
|
||||||
|
// address: String,
|
||||||
|
// name: String,
|
||||||
|
//}
|
||||||
|
//#[derive(Deserialize, Clone)]
|
||||||
|
//struct MaildevEmail {
|
||||||
|
// id: String,
|
||||||
|
// from: Vec<MaildevAddress>,
|
||||||
|
// to: Vec<MaildevAddress>,
|
||||||
|
// subject: String,
|
||||||
|
// text: String,
|
||||||
|
// html: Option<String>,
|
||||||
|
//}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
struct MaildevAddress {
|
struct MailPitAddress {
|
||||||
|
#[serde(rename = "Address")]
|
||||||
address: String,
|
address: String,
|
||||||
|
#[serde(rename = "Name")]
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
struct MaildevEmail {
|
pub struct MailpitSummary {
|
||||||
|
#[serde(rename = "ID")]
|
||||||
id: String,
|
id: String,
|
||||||
from: Vec<MaildevAddress>,
|
#[serde(rename = "To")]
|
||||||
to: Vec<MaildevAddress>,
|
to: Vec<MailPitAddress>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub struct MailpitEmail {
|
||||||
|
#[serde(rename = "From")]
|
||||||
|
from: MailPitAddress,
|
||||||
|
#[serde(rename = "To")]
|
||||||
|
to: Vec<MailPitAddress>,
|
||||||
|
#[serde(rename = "ReplyTo")]
|
||||||
|
reply_to: Vec<MailPitAddress>,
|
||||||
|
#[serde(rename = "Subject")]
|
||||||
subject: String,
|
subject: String,
|
||||||
|
#[serde(rename = "Text")]
|
||||||
text: String,
|
text: String,
|
||||||
html: Option<String>,
|
#[serde(rename = "HTML")]
|
||||||
|
html: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub struct MailpitListEmails {
|
||||||
|
messages: Vec<MailpitSummary>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
pub struct MailpitDeleteEmail {
|
||||||
|
IDs: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
|
@ -77,21 +120,31 @@ mod tests {
|
||||||
|
|
||||||
let mut u = Url::parse(&maildev_url).unwrap();
|
let mut u = Url::parse(&maildev_url).unwrap();
|
||||||
|
|
||||||
u.set_path("/email");
|
u.set_path("/api/v1/messages");
|
||||||
let maildev_emails: Vec<MaildevEmail> =
|
let mailpit_emails: MailpitListEmails =
|
||||||
c.get(u.clone()).send().await.unwrap().json().await.unwrap();
|
c.get(u.clone()).send().await.unwrap().json().await.unwrap();
|
||||||
let maildev_email = maildev_emails
|
|
||||||
|
let mailpit_summary = mailpit_emails
|
||||||
|
.messages
|
||||||
.iter()
|
.iter()
|
||||||
.find(|e| e.to.iter().any(|f| f.address == email))
|
.find(|e| e.to.iter().any(|f| f.address == email))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(maildev_email.text.contains(validation_secret));
|
|
||||||
assert!(maildev_email.text.contains(username));
|
u.set_path(&format!("/api/v1/message/{}", mailpit_summary.id));
|
||||||
assert!(maildev_email
|
let mailpit_email: MailpitEmail =
|
||||||
|
c.get(u.clone()).send().await.unwrap().json().await.unwrap();
|
||||||
|
|
||||||
|
assert!(mailpit_email.text.contains(validation_secret));
|
||||||
|
assert!(mailpit_email.text.contains(username));
|
||||||
|
assert!(mailpit_email
|
||||||
.to
|
.to
|
||||||
.iter()
|
.iter()
|
||||||
.any(|t| t.address == email && t.name == username));
|
.any(|t| t.address == email && t.name == username));
|
||||||
|
|
||||||
u.set_path(&format!("/email/{}", maildev_email.id));
|
u.set_path("/api/v1/messages");
|
||||||
c.delete(u).send().await.unwrap();
|
let payload = MailpitDeleteEmail {
|
||||||
|
IDs: vec![mailpit_summary.id.clone()],
|
||||||
|
};
|
||||||
|
c.delete(u).json(&payload).send().await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue