Skip to content

Commit

Permalink
feat(provider): add mailgun provider (#6)
Browse files Browse the repository at this point in the history
Changelog
* Add mailgun provider struct
* Add provider error enum
* Add email notification struct
* Add thiserror dependancy to cargo.toml
  • Loading branch information
jonperron authored Nov 9, 2024
1 parent 14dfc51 commit 3333b49
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ version = "0.1.0"
edition = "2021"

[dependencies]
# Error handling
thiserror = "2.0.1"

# API
axum = "0.7.7"
hyper = { version = "1.5.0", features = ["full"] }
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod config;
mod templates;
mod providers;

use axum:: Router;
use crate::config::Config;
Expand Down
42 changes: 42 additions & 0 deletions src/providers/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::fmt;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum ProviderError {
#[error("Network error: {0}")]
NetworkError(String),

#[error("Invalid configuration: {0}")]
InvalidConfig(String),

#[error("Template error: {0}")]
TemplateError(String),

#[error("Unexpected error: {0}")]
UnexpectedError(String),

#[error["Api error: {0}"]]
ApiError(String)
}

impl ProviderError {
pub fn network_error(details: impl Into<String>) -> Self {
ProviderError::NetworkError(details.into())
}

pub fn invalid_config(details: impl Into<String>) -> Self {
ProviderError::InvalidConfig(details.into())
}

pub fn template_error(details: impl Into<String>) -> Self {
ProviderError::TemplateError(details.into())
}

pub fn unexpected_error(details: impl Into<String>) -> Self {
ProviderError::UnexpectedError(details.into())
}

pub fn api_error(details: impl Into<String>) -> Self {
ProviderError::ApiError(details.into())
}
}
60 changes: 60 additions & 0 deletions src/providers/mailgun.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use reqwest::Client;
use serde::Deserialize;

use crate::providers::EmailNotification;
use crate::providers::errors::ProviderError;

#[derive(Debug, Deserialize, Clone)]
pub struct MailgunConfig {
pub domain: String,
pub api_key: String,
pub base_url: Option<String>,
}

pub struct MailgunProvider {
config: MailgunConfig,
client: Client,
}

impl MailgunProvider {
pub fn new(config: MailgunConfig) -> Self {
let client = Client::new();
Self { config, client }
}

// Send notification to Mailgun API
async fn send_email(&self, notification: &EmailNotification) -> Result<(), ProviderError> {
let url = format!(
"{}/v3/{}/messages",
self.config.base_url.clone().unwrap_or_else(|| "https://api.mailgun.net".to_string()),
self.config.domain
);

let params = [
("from", &notification.from),
("to", &notification.to),
("subject", &notification.subject),
("text", &notification.body),
];

let response = self
.client
.post(&url)
.basic_auth("api", Some(&self.config.api_key))
.form(&params)
.send()
.await
.map_err(|e| ProviderError::NetworkError(e.to_string()))?;

if response.status().is_success() {
Ok(())
} else {
let status = response.status();
let text = response.text().await.unwrap_or_default();
Err(ProviderError::ApiError(format!(
"Mailgun API error: {} - {}",
status, text
)))
}
}
}
9 changes: 9 additions & 0 deletions src/providers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use serde:: {Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EmailNotification {
pub from: String,
pub to: String,
pub subject: String,
pub body: String,
}

0 comments on commit 3333b49

Please sign in to comment.