2 unstable releases

0.1.0 Jun 22, 2023
0.0.0 May 11, 2023

#99 in Email

Apache-2.0 and maybe AGPL-3.0-only

883 lines


Expose services through the email infrastructure.


The simple fact of setting up a custom service to allow users to use it is not easy. You need to deploy your server, pay for resources, host it through a public address, and provide a client application that they can use to interact with your service.

This is a lot of work and maintenance. Sometimes it can be justified, but sometimes the only purpose is to expose a simple service they can use, and you do not want to deal with all this amount of work.

mailfred tries to give a solution to this using the current email infrastructure. It reads emails from an email account, fetches them, processes them, and reply them back to the remitter. It does not act as an email server; it acts as a client (using SMTP and IMAP protocols) that connects to an email service provider. You don't need to set up and deploy a server email. You don't need to host anything or buy a public domain address to make it accessible (you can run it from your own home if you want). And more important, all your users already have your client application in their mobiles and computers: their own email client applications that they already know how to use.

How does it works?

mailfred is inspired by axum. It works as an HTTP server, but instead of connecting through a TCP transport on port 80, it is connected through IMAP and SMTP protocols on an email address.

Each email sent to that email address is fetched and interpreted as if it was an HTTP request. The request email is routed to the correct service using the subject. Once it is processed by the service, a new email is sent back to the remitter as if it was an HTTP response.



Getting started

Add the following to your Cargo.toml:

mailfred = "0.1"
tokio = { version = "1", features = ["full"] }

tokio is required to run the async tasks.


use mailfred::{
    router::{Router, layers::LowercaseHeader},
    service::{user_error, Request, Response, ResponseResult},
use tokio::sync::Mutex;
use std::sync::Arc;

struct MyState {
    counter: u32,

type State = Arc<Mutex<MyState>>;

async fn count(_: Request, state: State) -> ResponseResult {
    let mut state = state.lock().await;
    state.counter += 1;

    Response::ok("Counter stats", format!("Value: {}", state.counter))

async fn echo(req: Request, _: State) -> ResponseResult {
    Response::ok(req.header, req.body)

async fn main() -> Result<(), anyhow::Error> {
    let gmail = Gmail {
        username: "user".into(),
        password: "1234".into(),

    let router = Router::default()
        .route("Count", count)
        .route("Echo", echo)

    mailfred::serve(gmail, State::default(), router).await

Gmail account configuration

If you want to use a Gmail account, you need to set up some things before:

  1. Create a new account, do NOT use your normal account. The mailfred's IMAP transport removes the messages it reads from the inbox.
  2. Enable IMAP in the Gmail configuration.
  3. Enable Gmail's app passwords for the account.


~309K SLoC