Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E-mail support #276

Open
1 of 4 tasks
joepio opened this issue Jan 7, 2022 · 2 comments
Open
1 of 4 tasks

E-mail support #276

joepio opened this issue Jan 7, 2022 · 2 comments

Comments

@joepio
Copy link
Member

joepio commented Jan 7, 2022

At some point, we'll want to send e-mails. For notifications, registrations, or newsletters, for example.

Usecases for sending mails

  • E-mail confirmation for Agents. On creating an Agent, send an e-mail. With a confirmed e-email, we can send password / key reset mails.
  • Share / invite with a custom message.
  • Follow something, receive updates when it changes. Think newsletters / blogs / notifications.
  • Custom e-mails from plugins, e.g. your export is ready to download

Usecases for receiving mail

  • A unique / friendly API to store thoughts: send mails to some specified endpoint to create new textual resources + attachments.
  • A full on e-mail client. As atomic-server is like a personal server, it kind of makes sense for it to do mails, too. But it also feels like huge scope creep.

Implementation

I think it makes sense to offer an e-mail API at the plugin level.
Not sure what that means, as at the very least, some sort of server listening to a specific set of ports will need to be started.
Maybe atomic-lib may need a runtime, too, at some point, as now only atomic-server does.

Plugins should be able to send e-mails. That means that plugins need access to the mailed functions and SMTP connection state. So that probably means that we need the mailer to be available from Db. We could set a mailer Db::init, which means we need some extra arguments there, or we could set it on a separate function, at Db::set_mailer.

Email for registration / verification

  • Before validating a drive, make sure the e-mail is confirmed
  • Create a confirmation token / link that can only be used once. If it is opened, confirm the e-mail address for the agent that requested it.
  • If we make something like a VerificationRequest resource that represents this URL, we need to make sure that it is not indexed, similar to Invites. See #235
  • I'd love to support Oauth / OpenID connect (OIDC), so users could sign in with google / github / whatever. Not sure if that is relevant, but I should read up on it. See Consider supporting OIDC / SSO / Oauth #277

Crates

@joepio
Copy link
Member Author

joepio commented Nov 22, 2022

I've managed to get mail-send working with a local SMTP server (although not properly embedded in Atomic-Server).

But if I use mailin_embedded, the process doesn't exit:

use mailin_embedded::{AuthMechanism, Handler, Server, SslConfig};
use tracing::info;

use crate::errors::AtomicServerResult;

#[derive(Clone)]
struct MailHandler {}
impl Handler for MailHandler {}

const ADDRESS: &str = "127.0.0.1:12041";
const ADDRESS_MAILCATCHER: &str = "127.0.0.1:1025";

pub fn start_mail_server() -> AtomicServerResult<()> {
    let handler = MailHandler {};
    let mut server = Server::new(handler);
    let address = ADDRESS;

    server
        .with_name("example.com")
        .with_auth(AuthMechanism::Plain)
        .with_ssl(SslConfig::None)
        .map_err(|e| format!("Mail SSL error: {e}"))?
        .with_addr(address)
        .map_err(|e| format!("Mail address error: {e}"))?;

    tokio::spawn(async move { send_mail().await });

    tokio::task::spawn_blocking(move || {
        info!("Starting mail server at {address}");
        // TODO: stop this process on ctrl+C
        server.serve().expect("Failed to start mail server");
    });

    Ok(())
}

@joepio
Copy link
Member Author

joepio commented Nov 25, 2022

I've got an SMTP client in atomic-lib working, so we can use it from Endpoint plugins.

However, I'm having doubts on the API to use for send_mail. Specifically, I'm not sure if I should use async (#424)

Since the plugin itself is not async, the code becomes pretty verbose, and we're cloning the Store:

    let store_clone = store.clone();
    tokio::spawn(async move {
        store_clone
            .send_email(message)
            .await
            .unwrap_or_else(|e| tracing::error!("Error sending email: {}", e));
    });

If it was just sync, we'd get something like this, but the response would have to wait for the SMTP server. Slow!

store.send_email(message)?;

But in the future, we should expect plugins to do async stuff without blocking the whole thread.

@joepio joepio added this to the Eurostars Deliverables milestone Sep 29, 2023
@joepio joepio removed this from the _ milestone Nov 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant