xrpcs-emailer#
An ATProtocol XRPC service that sends emails for smokesignal.events.
Overview#
This emailer service is a lightweight microservice that handles webhook events from the smokesignal.events platform and sends notification emails. The service currently processes RSVP confirmations and sends email notifications to event attendees.
Key features:
- Webhook event processing endpoint
- OAuth-based authentication and authorization
- DID:web identity publication
- SMTP email integration
- RSVP confirmation email notifications
- Configurable via environment variables
Administrator's Guide#
Generating Service Keys#
Before configuring the service, you'll need to generate a cryptographic key for the service identity:
# Generate a new P-256 service key
goat key generate -t p256
This command will output a private key that you'll use for the SERVICE_KEY configuration.
Important: The public key derived from your service key is automatically included in the service's DID:web document, allowing other services to verify the service's identity.
For more information on ATProtocol key management and DID documents, see: https://whtwnd.com/bnewbold.net/3lj7jmt2ct72r
Configuration#
The service requires the following environment variables:
| Variable | Required | Description |
|---|---|---|
SERVICE_KEY |
Yes | Private key for the service's identity (e.g., did:key:z42tj..) |
EXTERNAL_BASE |
Yes | External hostname where the service is accessible (e.g., emailer.example.com) |
SMTP_CREDENTIALS |
Yes | SMTP connection URL (e.g., smtp://username:password@smtp.server:port) |
PORT |
No | HTTP server port (default: 8080) |
PLC_HOSTNAME |
No | PLC directory hostname (default: plc.directory) |
USER_AGENT |
No | HTTP User-Agent header for external requests |
DNS_NAMESERVERS |
No | Comma-separated list of DNS nameservers |
CERTIFICATE_BUNDLES |
No | Comma-separated list of additional CA certificate bundle paths |
Building and Running#
Local Development#
# Clone the repository
git clone https://tangled.sh/@smokesignal.events/xrpcs-emailer
cd xrpcs-emailer
# Build the project
cargo build --release
# Run with environment variables
SERVICE_KEY="did:key:your-service-key" \
EXTERNAL_BASE="emailer.example.com" \
SMTP_CREDENTIALS="smtp://username:password@smtp.server:port" \
cargo run --release
Docker Container#
The project includes a multi-stage Dockerfile that builds a minimal container using distroless base image.
# Build the container
docker build --pull -t xrpcs-emailer .
# Run the container
docker run -d \
-p 8080:8080 \
-e SERVICE_KEY="did:key:your-service-key" \
-e EXTERNAL_BASE="emailer.example.com" \
-e SMTP_CREDENTIALS="smtp://username:password@smtp.server:port" \
xrpcs-emailer
Deployment Considerations#
-
TLS Termination: The service runs HTTP internally. Use a reverse proxy (nginx, Caddy, etc.) for TLS termination.
-
Health Checks: The root endpoint (
/) can be used for health checks. -
Monitoring: The service logs important events using the
tracingcrate. Configure log levels via theRUST_LOGenvironment variable. -
Key Security: Store private keys securely. Consider using environment variable secrets management in production.
-
SMTP Security: Use secure SMTP connections (SMTPS) when possible and store credentials securely.
Integrator's Guide#
XRPC Method Definition#
The service provides a single XRPC method: events.smokesignal.automation.InvokeWebhook
This webhook endpoint accepts JSON payloads containing event information and processes them accordingly. Currently supported events:
rsvp.created: Sends confirmation email to the attendee
Authentication#
The service uses OAuth 2.0 bearer token authentication to protect the webhook endpoint.
Making Requests#
Example using curl#
# Send webhook for RSVP created event
curl -X POST https://emailer.example.com/xrpc/events.smokesignal.automation.InvokeWebhook \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event": "rsvp.created",
"context": {
"email": "attendee@example.com"
}
}'
Error Responses#
The service returns standard HTTP status codes:
200 OK: Webhook processed successfully401 Unauthorized: Missing or invalid authentication
Error responses include a JSON body:
{
"error": "unauthorized",
"error_description": "authentication is required"
}
Service Discovery#
The service publishes its identity via:
/.well-known/did.json- DID:web document/.well-known/atproto-did- ATProtocol DID identifier/.well-known/oauth-protected-resource- OAuth Protected Resource Metadata
Email Details#
For RSVP confirmations, the service sends emails with:
- From: "Smoke Signal Emailer" events@smokesignal.events
- Subject: "RSVP'd to event"
- Body: Multipart message containing both plain text and HTML versions with a thank you message
License#
This project is open source under the MIT License.
MIT License
Copyright (c) 2025 Nick Gerakines
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.