Skip to content

davecaos/lumenmail

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LumenMail

A Gleam library for sending emails via SMTP, inspired by the Rust mail-send crate.

Package Version Hex Docs

Features

  • Direct SMTP connections with TLS/SSL support
  • STARTTLS and implicit TLS (port 465)
  • Multiple authentication mechanisms (PLAIN, LOGIN, CRAM-MD5, XOAUTH2)
  • HTML and plain text emails
  • File attachments and inline images
  • Custom headers
  • Email threading (In-Reply-To, References)
  • RFC 5322 compliant message formatting
  • Connection reuse for sending multiple emails

Installation

Add lumenmail to your Gleam project:

gleam add lumenmail

Quick Start

import lumenmail/message
import lumenmail/smtp

pub fn main() {
  // Build the email message
  let email = message.new()
    |> message.from_name_email("John Doe", "[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Hello from Gleam!")
    |> message.text_body("This is a test email sent with lumenmail.")

  // Connect to SMTP server and send
  let assert Ok(client) = smtp.builder("smtp.example.com", 587)
    |> smtp.auth("username", "password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

Examples

Simple Text Email

import lumenmail/message
import lumenmail/smtp

pub fn send_simple_email() {
  let email = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Hello!")
    |> message.text_body("This is a plain text email.")

  let assert Ok(client) = smtp.builder("smtp.example.com", 587)
    |> smtp.auth("user", "password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

HTML Email with Plain Text Fallback

import lumenmail/message
import lumenmail/smtp

pub fn send_html_email() {
  let email = message.new()
    |> message.from_name_email("Newsletter", "[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Weekly Newsletter")
    |> message.text_body("Your weekly update in plain text.")
    |> message.html_body("<h1>Weekly Newsletter</h1><p>Your weekly update!</p>")

  let assert Ok(client) = smtp.builder("smtp.example.com", 587)
    |> smtp.auth("user", "password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

Email with Attachments

import lumenmail/message
import lumenmail/smtp

pub fn send_with_attachment() {
  let pdf_data = <<...>>  // Your PDF file as BitArray

  let email = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Document Attached")
    |> message.text_body("Please find the document attached.")
    |> message.attachment("document.pdf", message.ApplicationOctetStream, pdf_data)

  let assert Ok(client) = smtp.builder("smtp.example.com", 587)
    |> smtp.auth("user", "password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

Multiple Recipients (To, CC, BCC)

import lumenmail/message
import lumenmail/smtp

pub fn send_to_multiple() {
  let email = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.to_name_email("Jane Doe", "[email protected]")
    |> message.cc_email("[email protected]")
    |> message.bcc_email("[email protected]")
    |> message.subject("Team Update")
    |> message.text_body("Hello team!")

  let assert Ok(client) = smtp.builder("smtp.example.com", 587)
    |> smtp.auth("user", "password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

Using Gmail with App Password

import lumenmail/message
import lumenmail/smtp

pub fn send_via_gmail() {
  let email = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Sent from Gmail")
    |> message.text_body("Hello from Gmail!")

  // Gmail uses port 587 with STARTTLS
  let assert Ok(client) = smtp.builder("smtp.gmail.com", 587)
    |> smtp.auth("[email protected]", "your-app-password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

Using Implicit TLS (Port 465)

import lumenmail/message
import lumenmail/smtp

pub fn send_with_implicit_tls() {
  let email = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Secure Email")
    |> message.text_body("Sent over implicit TLS.")

  // Port 465 automatically uses implicit TLS
  let assert Ok(client) = smtp.builder("smtp.example.com", 465)
    |> smtp.auth("user", "password")
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

OAuth2 Authentication

import lumenmail/message
import lumenmail/smtp
import lumenmail/types

pub fn send_with_oauth2() {
  let email = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("OAuth2 Email")
    |> message.text_body("Sent using OAuth2!")

  let assert Ok(client) = smtp.builder("smtp.gmail.com", 587)
    |> smtp.credentials(types.OAuth2("[email protected]", "oauth2-access-token"))
    |> smtp.connect()

  let assert Ok(_) = smtp.send(client, email)
  let assert Ok(_) = smtp.close(client)
}

Sending Multiple Emails (Connection Reuse)

import lumenmail/message
import lumenmail/smtp

pub fn send_multiple_emails() {
  let assert Ok(client) = smtp.builder("smtp.example.com", 587)
    |> smtp.auth("user", "password")
    |> smtp.connect()

  // Send first email
  let email1 = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Email 1")
    |> message.text_body("First email")

  let assert Ok(_) = smtp.send(client, email1)

  // Reset connection state
  let assert Ok(_) = smtp.reset(client)

  // Send second email
  let email2 = message.new()
    |> message.from_email("[email protected]")
    |> message.to_email("[email protected]")
    |> message.subject("Email 2")
    |> message.text_body("Second email")

  let assert Ok(_) = smtp.send(client, email2)
  let assert Ok(_) = smtp.close(client)
}

API Reference

Message Builder

Function Description
message.new() Create a new empty message
message.from_email(msg, email) Set sender email
message.from_name_email(msg, name, email) Set sender with display name
message.to_email(msg, email) Add To recipient
message.to_name_email(msg, name, email) Add To recipient with name
message.cc_email(msg, email) Add CC recipient
message.bcc_email(msg, email) Add BCC recipient
message.subject(msg, subject) Set subject line
message.text_body(msg, text) Set plain text body
message.html_body(msg, html) Set HTML body
message.attachment(msg, filename, content_type, data) Add file attachment
message.inline_attachment(msg, filename, content_type, data, content_id) Add inline attachment
message.header(msg, name, value) Add custom header
message.priority(msg, priority) Set email priority
message.reply_to(msg, address) Set Reply-To address

SMTP Client Builder

Function Description
smtp.builder(host, port) Create SMTP client builder
smtp.auth(builder, username, password) Set authentication credentials
smtp.credentials(builder, creds) Set credentials (Plain or OAuth2)
smtp.implicit_tls(builder, enabled) Enable/disable implicit TLS
smtp.timeout(builder, ms) Set connection timeout
smtp.helo_host(builder, hostname) Set HELO hostname
smtp.allow_invalid_certs(builder, allow) Allow invalid TLS certs (testing only)
smtp.connect(builder) Connect to SMTP server

SMTP Client Operations

Function Description
smtp.send(client, message) Send an email message
smtp.send_raw(client, from, to, data) Send raw email data
smtp.reset(client) Reset connection for next email
smtp.noop(client) Send NOOP to keep connection alive
smtp.close(client) Close the connection
smtp.capabilities(client) Get server capabilities

Common SMTP Ports

Port Protocol Description
25 SMTP Standard SMTP (often blocked by ISPs)
587 Submission SMTP with STARTTLS (recommended)
465 SMTPS SMTP over implicit TLS

Development

gleam test  # Run the tests
gleam build # Build the project

License

Apache-2.0 OR MIT

About

A Gleam library for sending emails via SMTP, inspired by the Rust [mail-send](https://docs.rs/mail-send/latest/mail_send/) crate.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors