//! Email suppression list populated by Postmark bounce/complaint webhooks. use sqlx::PgPool; use crate::error::Result; /// Check if an email address is on the suppression list. #[tracing::instrument(skip_all)] pub async fn is_suppressed(pool: &PgPool, email: &str) -> Result { let row = sqlx::query_scalar::<_, bool>( "SELECT EXISTS(SELECT 1 FROM email_suppressions WHERE email = LOWER($1))", ) .bind(email) .fetch_one(pool) .await?; Ok(row) } /// Record a suppressed email address. Idempotent; does nothing if already suppressed. #[tracing::instrument(skip_all)] pub async fn add_suppression(pool: &PgPool, email: &str, reason: &str) -> Result<()> { sqlx::query( r#" INSERT INTO email_suppressions (email, reason) VALUES (LOWER($1), $2) ON CONFLICT ((LOWER(email))) DO NOTHING "#, ) .bind(email) .bind(reason) .execute(pool) .await?; Ok(()) }