Skip to main content

max / makenotwork

957 B · 37 lines History Blame Raw
1 //! Email suppression list populated by Postmark bounce/complaint webhooks.
2
3 use sqlx::PgPool;
4
5 use crate::error::Result;
6
7 /// Check if an email address is on the suppression list.
8 #[tracing::instrument(skip_all)]
9 pub async fn is_suppressed(pool: &PgPool, email: &str) -> Result<bool> {
10 let row = sqlx::query_scalar::<_, bool>(
11 "SELECT EXISTS(SELECT 1 FROM email_suppressions WHERE email = LOWER($1))",
12 )
13 .bind(email)
14 .fetch_one(pool)
15 .await?;
16
17 Ok(row)
18 }
19
20 /// Record a suppressed email address. Idempotent; does nothing if already suppressed.
21 #[tracing::instrument(skip_all)]
22 pub async fn add_suppression(pool: &PgPool, email: &str, reason: &str) -> Result<()> {
23 sqlx::query(
24 r#"
25 INSERT INTO email_suppressions (email, reason)
26 VALUES (LOWER($1), $2)
27 ON CONFLICT ((LOWER(email))) DO NOTHING
28 "#,
29 )
30 .bind(email)
31 .bind(reason)
32 .execute(pool)
33 .await?;
34
35 Ok(())
36 }
37