Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1d2849e
Initial commit of email.rs using lettre
trkelly23 Mar 15, 2025
252cebe
Initial commit of Add email support using lettre crate
trkelly23 Mar 15, 2025
fc1fb9f
Added the message printout if debug mode is enabled
trkelly23 Mar 16, 2025
d64980f
Added a test and deferred the extra headers and attachment features.
trkelly23 Mar 18, 2025
4edd6d0
Added tests for config and send_email(ignore).
trkelly23 Mar 19, 2025
dbbf50f
Fixed the email example and removed minor version from cargo.
trkelly23 Mar 19, 2025
0587340
chore(pre-commit.ci): auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 20, 2025
a1a25da
Fixed the email example and removed minor version from cargo.
trkelly23 Mar 15, 2025
84eb659
Merge branch 'feat-add-email-support' of https://github.com/trkelly23…
trkelly23 Mar 20, 2025
c964e45
chore(pre-commit.ci): auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 20, 2025
a13552e
Implemented a trait impl for the EmailBackend
trkelly23 Mar 20, 2025
6ac6e92
chore(pre-commit.ci): auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 20, 2025
d7ac14a
Refactor to insure multiple email backends could be added. Mocking a…
trkelly23 Mar 28, 2025
4ee5c6a
Pushing lock since there seems to be a conflict
trkelly23 Mar 28, 2025
49775cd
Merge branch 'master' into feat-add-email-support
trkelly23 Mar 28, 2025
553c2e9
chore(pre-commit.ci): auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 28, 2025
cb8093a
Adding the reworked smtp implementation and NOT working example for h…
trkelly23 May 8, 2025
749ef05
chore: cargo fmt
seqre May 15, 2025
3a042af
fix bootstrapper
seqre May 15, 2025
84c111d
chore: merge master
seqre May 15, 2025
ea8e2e0
chore(pre-commit.ci): auto fixes from pre-commit hooks
pre-commit-ci[bot] May 15, 2025
fa4f337
Merge branch 'master' into feat-add-email-support
m4tx May 15, 2025
6cc9cb6
Merge branch 'master' into feat-add-email-support
seqre May 15, 2025
83652f1
Tested send-email example and cleaned up code
trkelly23 May 28, 2025
33e49c2
Merge branch 'master' into feat-add-email-support
trkelly23 May 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 227 additions & 162 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
# Examples
"examples/admin",
"examples/custom-error-pages",
"examples/send-email",
"examples/custom-task",
"examples/file-upload",
"examples/hello-world",
Expand Down Expand Up @@ -92,6 +93,7 @@ humantime = "2"
indexmap = "2"
insta = { version = "1", features = ["filters"] }
insta-cmd = "0.6"
lettre = { version = "0.11", features = ["smtp-transport", "builder", "native-tls"] }
mime_guess = { version = "2", default-features = false }
mockall = "0.13"
multer = "3"
Expand Down
1 change: 1 addition & 0 deletions cot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ http-body.workspace = true
http.workspace = true
humantime.workspace = true
indexmap.workspace = true
lettre.workspace = true
mime_guess.workspace = true
multer.workspace = true
password-auth = { workspace = true, features = ["std", "argon2"] }
Expand Down
121 changes: 121 additions & 0 deletions cot/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use derive_more::with_trait::{Debug, From};
use serde::{Deserialize, Serialize};
use subtle::ConstantTimeEq;

use crate::email;

/// The configuration for a project.
///
/// This is all the project-specific configuration data that can (and makes
Expand Down Expand Up @@ -211,6 +213,24 @@ pub struct ProjectConfig {
/// # Ok::<(), cot::Error>(())
/// ```
pub middlewares: MiddlewareConfig,
/// Configuration related to the email backend.
///
/// # Examples
///
/// ```
/// use cot::config::{EmailBackendConfig, ProjectConfig};
///
/// let config = ProjectConfig::from_toml(
/// r#"
/// [email_backend]
/// type = "none"
/// "#,
/// )?;
///
/// assert_eq!(config.email_backend, EmailBackendConfig::default());
/// # Ok::<(), cot::Error>(())
/// ```
pub email_backend: EmailBackendConfig,
}

const fn default_debug() -> bool {
Expand Down Expand Up @@ -313,6 +333,7 @@ impl ProjectConfigBuilder {
database: self.database.clone().unwrap_or_default(),
static_files: self.static_files.clone().unwrap_or_default(),
middlewares: self.middlewares.clone().unwrap_or_default(),
email_backend: self.email_backend.clone().unwrap_or_default(),
}
}
}
Expand Down Expand Up @@ -809,7 +830,104 @@ impl SessionMiddlewareConfigBuilder {
}
}
}
/// The type of email backend to use.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum EmailBackendType {
/// No email backend.
#[default]
None,
/// SMTP email backend.
Smtp,
}
/// The configuration for the SMTP backend.
///
/// This is used as part of the [`EmailBackendConfig`] enum.
///
/// # Examples
///
/// ```
/// use cot::config::EmailBackendConfig;
///
/// let config = EmailBackendConfig::builder().build();
/// ```
#[derive(Debug, Default, Clone, PartialEq, Eq, Builder, Serialize, Deserialize)]
#[builder(build_fn(skip, error = std::convert::Infallible))]
#[serde(default)]
pub struct EmailBackendConfig {
/// The type of email backend to use.
/// Defaults to `None`.
#[builder(setter(into, strip_option), default)]
pub backend_type: EmailBackendType,
/// The SMTP server host address.
/// Defaults to "localhost".
#[builder(setter(into, strip_option), default)]
pub smtp_mode: email::SmtpTransportMode,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests to ensure all variants of this enum can be constructed from TOML.

/// The SMTP server port.
/// Overwrites the default standard port when specified.
#[builder(setter(into, strip_option), default)]
pub port: Option<u16>,
/// The username for SMTP authentication.
#[builder(setter(into, strip_option), default)]
pub username: Option<String>,
/// The password for SMTP authentication.
#[builder(setter(into, strip_option), default)]
pub password: Option<String>,
/// The timeout duration for the SMTP connection.
#[builder(setter(into, strip_option), default)]
pub timeout: Option<Duration>,
}

impl EmailBackendConfig {
/// Create a new [`EmailBackendConfigBuilder`] to build a
/// [`EmailBackendConfig`].
///
/// # Examples
///
/// ```
/// use cot::config::EmailBackendConfig;
///
/// let config = EmailBackendConfig::builder().build();
/// ```
#[must_use]
pub fn builder() -> EmailBackendConfigBuilder {
EmailBackendConfigBuilder::default()
}
}
impl EmailBackendConfigBuilder {
/// Builds the email configuration.
///
/// # Examples
///
/// ```
/// use cot::config::EmailBackendConfig;
///
/// let config = EmailBackendConfig::builder().build();
/// ```
#[must_use]
pub fn build(&self) -> EmailBackendConfig {
match self.backend_type.clone().unwrap_or(EmailBackendType::None) {
EmailBackendType::Smtp => EmailBackendConfig {
backend_type: EmailBackendType::Smtp,
smtp_mode: self
.smtp_mode
.clone()
.unwrap_or(email::SmtpTransportMode::Localhost),
port: self.port.unwrap_or_default(),
username: self.username.clone().unwrap_or_default(),
password: self.password.clone().unwrap_or_default(),
timeout: self.timeout.unwrap_or_default(),
},
EmailBackendType::None => EmailBackendConfig {
backend_type: EmailBackendType::None,
smtp_mode: email::SmtpTransportMode::Localhost,
port: None,
username: None,
password: None,
timeout: None,
},
}
}
}
/// A secret key.
///
/// This is a wrapper over a byte array, which is used to store a cryptographic
Expand Down Expand Up @@ -1024,6 +1142,8 @@ mod tests {
live_reload.enabled = true
[middlewares.session]
secure = false
[email_backend]
type = "none"
"#;

let config = ProjectConfig::from_toml(toml_content).unwrap();
Expand All @@ -1046,6 +1166,7 @@ mod tests {
);
assert!(config.middlewares.live_reload.enabled);
assert!(!config.middlewares.session.secure);
assert_eq!(config.email_backend.backend_type, EmailBackendType::None);
}

#[test]
Expand Down
Loading
Loading