Sending Emails
Mailer Drivers
Section titled “Mailer Drivers”PlaceOS provides two primary drivers for sending email:
- SMTP Mailer — sends direct emails
- Template Mailer — resolves templates and delegates delivery to another mailer (typically SMTP)
Email delivery is exposed through the shared:
PlaceOS::Driver::Interface::MailerDrivers that want to publish available template fields implement:
PlaceOS::Driver::Interface::MailerTemplatesArchitecture Overview
Section titled “Architecture Overview”Typical deployment:
Custom Driver │ │ send_template(...) ▼Template Mailer │ │ send_mail(...) ▼SMTP Mailer │ ▼SMTP ServerFlow Summary
Section titled “Flow Summary”Direct Email
Section titled “Direct Email”Custom Driver → SMTP Mailer → SMTP ServerTemplate Email
Section titled “Template Email”Custom Driver → Template Mailer → SMTP Mailer → SMTP ServerSMTP Mailer
Section titled “SMTP Mailer”Driver:
drivers/place/smtp.crInterface:
PlaceOS::Driver::Interface::MailerThe SMTP mailer sends standard email messages with:
- Plain text content
- HTML content
- Attachments
- Inline resources
- CC / BCC
- Custom sender and reply-to
SMTP Driver Configuration
Section titled “SMTP Driver Configuration”Example settings:
---sender: "support@example.com"
host: "smtp.example.com"port: 587
tls_mode: "STARTTLS"
username: "smtp-user"password: "smtp-password"
ssl_verify_ignore: falseSettings
Section titled “Settings”| Setting | Description |
|---|---|
sender | Default from address |
host | SMTP server hostname |
port | SMTP port |
tls_mode | NONE, SSL, or STARTTLS |
username | SMTP username (optional) |
password | SMTP password (optional) |
ssl_verify_ignore | Disable certificate verification |
Sending Direct Email
Section titled “Sending Direct Email”Use when subject and content are known at runtime.
Example Driver
Section titled “Example Driver”require "placeos-driver"require "placeos-driver/interface/mailer"
class Example::AlertMailer < PlaceOS::Driver descriptive_name "Example Alert Mailer" generic_name :AlertMailer
def mailer system.implementing( PlaceOS::Driver::Interface::Mailer )[0] end
def send_alert( email : String, room_name : String, fault : String ) mailer.send_mail( to: email, subject: "Fault detected in #{room_name}",
message_plaintext: "Fault detected: #{fault}",
message_html: <<-HTML <h1>Fault detected</h1> <p>Room: <strong>#{room_name}</strong></p> <p>Fault: #{fault}</p> HTML ) endendsend_mail Method
Section titled “send_mail Method”send_mail( to : String | Array(String),
subject : String,
message_plaintext : String? = nil, message_html : String? = nil,
resource_attachments : Array(ResourceAttachment) = [] of ResourceAttachment,
attachments : Array(Attachment) = [] of Attachment,
cc : String | Array(String) = [] of String, bcc : String | Array(String) = [] of String,
from : String | Array(String) | Nil = nil, reply_to : String | Array(String) | Nil = nil,)Attachments
Section titled “Attachments”Attachments must be Base64 encoded.
require "base64"
def send_report( email : String, pdf_bytes : Bytes) mailer.send_mail( to: email,
subject: "Daily report",
message_plaintext: "Attached is your report.",
attachments: [ { file_name: "report.pdf", content: Base64.strict_encode(pdf_bytes), } ] )endInline Resources
Section titled “Inline Resources”Used for embedded images in HTML.
require "base64"
def send_badge( email : String, png_bytes : Bytes) mailer.send_mail( to: email,
subject: "Badge",
message_html: %(<img src="cid:badge_image" />),
resource_attachments: [ { file_name: "badge.png", content: Base64.strict_encode(png_bytes), content_id: "badge_image", } ] )endTemplate Mailer
Section titled “Template Mailer”Driver:
drivers/place/template_mailer.crInterface:
PlaceOS::Driver::Interface::MailerTemplatesThe Template Mailer:
- Receives
send_template(...) - Finds matching template
- Expands fields
- Sends via downstream mailer
Typically:
Template Mailer → SMTP MailerTemplate Resolution
Section titled “Template Resolution”Templates are resolved in order:
- Level
- Building
- Region
- Organisation
The most specific match is used.
Defining Template Fields
Section titled “Defining Template Fields”Custom drivers define available fields using:
PlaceOS::Driver::Interface::MailerTemplatesThis enables UI configuration of templates.
Example Template Definition
Section titled “Example Template Definition”require "placeos-driver"require "placeos-driver/interface/mailer"require "placeos-driver/interface/mailer_templates"
class Example::BookingMailer < PlaceOS::Driver include PlaceOS::Driver::Interface::MailerTemplates
descriptive_name "Booking Mailer" generic_name :BookingMailer
def mailer system.implementing( PlaceOS::Driver::Interface::Mailer )[0] end
def template_fields [ TemplateFields.new( trigger: {"bookings", "approved"},
name: "Booking approved",
description: "Sent when booking approved",
fields: [ { name: "user_name", description: "Recipient name" }, { name: "room_name", description: "Room name" }, { name: "start_time", description: "Booking start" } ] ) ] endendSending Template Email
Section titled “Sending Template Email”Use when subject and content are externally managed.
def send_booking_email( email : String, user_name : String, room_name : String, start_time : String) mailer.send_template( to: email,
template: {"bookings", "approved"},
args: { "user_name" => user_name, "room_name" => room_name, "start_time" => start_time, } )endsend_template Method
Section titled “send_template Method”send_template( to : String | Array(String),
template : Tuple(String, String),
args : TemplateItems,
resource_attachments : Array(ResourceAttachment) = [] of ResourceAttachment,
attachments : Array(Attachment) = [] of Attachment,
cc : String | Array(String) = [] of String, bcc : String | Array(String) = [] of String,
from : String | Array(String) | Nil = nil, reply_to : String | Array(String) | Nil = nil,)Template Format
Section titled “Template Format”Templates use:
%{field_name}Example metadata:
[ { "trigger": "bookings.approved",
"subject": "Booking approved for %{room_name}",
"text": "Hi %{user_name}, your booking starts at %{start_time}.",
"html": "<p>Hi %{user_name}</p><p>Your booking starts at %{start_time}</p>",
"from": "bookings@example.com",
"reply_to": "support@example.com" }]Template Fallback Behaviour
Section titled “Template Fallback Behaviour”If the Template Mailer:
- cannot find metadata template
then:
send_template(...)is forwarded to the downstream mailer.
This allows fallback templates defined in:
email_templates:Minimal SMTP Template Fallback
Section titled “Minimal SMTP Template Fallback”---email_templates:
bookings:
approved:
subject: "Booking approved for %{room_name}"
text: "Hi %{user_name}, your booking starts at %{start_time}"
html: "<p>Hi %{user_name}</p><p>Your booking starts at %{start_time}</p>"Choosing the Right Method
Section titled “Choosing the Right Method”Use send_mail when:
Section titled “Use send_mail when:”- content generated in driver
- no UI-editable templates required
- simple delivery logic
mailer.send_mail(...)Use send_template when:
Section titled “Use send_template when:”- content managed outside driver
- templates editable in UI
- reusable email formats required
mailer.send_template(...)Best Practices
Section titled “Best Practices”- Always resolve the mailer using:
system.implementing( PlaceOS::Driver::Interface::Mailer)- Prefer templates for user-facing emails
- Use direct mail for operational alerts
- Base64 encode all attachments
- Provide descriptive template fields
- Keep template triggers consistent
Related Drivers
Section titled “Related Drivers”-
SMTP Mailer
drivers/place/smtp.cr -
Template Mailer
drivers/place/template_mailer.cr -
Example Template Driver
drivers/place/survey_mailer.cr
Related Interfaces
Section titled “Related Interfaces”-
Mailer Interface
interface/mailer.cr -
Mailer Templates Interface
interface/mailer_templates.cr