OpenTelemetry tracing and metrics plugin for the Haraka SMTP server.
Instruments the full SMTP lifecycle, from TCP connection through queue delivery, and exports spans and metrics to any OTLP-compatible backend.
- One span per SMTP connection with per-message events (
HELO/EHLO,MAIL FROM,RCPT TO,DATA,QUEUE) - Span attributes for client/server address, port, and message size
- Six out-of-the-box metrics covering connections, hook invocations, connection duration, message size, delivery results, and liveness
- Traces and metrics can each be disabled independently via config
- Zero code changes required: endpoint and auth are wired via standard OTEL environment variables
- Compatible with Jaeger, Grafana Tempo, HyperDX, Honeycomb, Datadog, and any other OTLP HTTP backend
- Node.js >= 22
- Haraka SMTP server
Navigate to your Haraka installation directory:
cd /path/to/local/harakaInstall the plugin:
npm install haraka-plugin-opentelemetryRegister the plugin:
echo "opentelemetry" >> config/pluginsRestart Haraka:
service haraka restartCopy the default config into your Haraka config directory:
cp node_modules/haraka-plugin-opentelemetry/config/opentelemetry.ini config/opentelemetry.ini[main]
; Set to false to disable the plugin entirely
enabled = true
; OTel resource attributes identifying this service
service_name = haraka
service_version = 1.0.0
; Extra resource attributes as comma-separated key=value pairs
; resource_attributes = env=production,region=us-east-1
[traces]
; Set to false to disable trace export without removing the plugin
enabled = true
[metrics]
; Set to false to disable metric export without removing the plugin
enabled = true
; How often metrics are pushed, in milliseconds
export_interval_ms = 60000Endpoint, authentication, and other export settings follow the standard OTLP exporter spec. These take precedence over opentelemetry.ini resource attributes.
| Variable | Default | Description |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4318 |
Base endpoint for all signals |
OTEL_EXPORTER_OTLP_HEADERS |
Auth/routing headers for all signals (key=val,key2=val2) |
|
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
Trace-specific endpoint override | |
OTEL_EXPORTER_OTLP_TRACES_HEADERS |
Trace-specific headers override | |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
Metrics-specific endpoint override | |
OTEL_EXPORTER_OTLP_METRICS_HEADERS |
Metrics-specific headers override | |
OTEL_SERVICE_NAME |
Overrides service.name resource attribute |
|
OTEL_RESOURCE_ATTRIBUTES |
Additional resource attributes (k=v,k2=v2) |
Each inbound SMTP connection produces one smtp.connection span (kind: SERVER) that covers the full connection lifetime. SMTP protocol events are recorded as span events on that root span.
| Attribute | Description |
|---|---|
client.address |
Remote client IP |
client.port |
Remote client port |
net.peer.name |
Remote hostname |
server.address |
Local server IP |
server.port |
Local server port |
smtp.message.size_bytes |
Message body size in bytes (set after DATA) |
| Event | Attributes |
|---|---|
smtp.helo / smtp.ehlo |
smtp.helo_host |
smtp.mail |
smtp.mail_from |
smtp.rcpt |
smtp.rcpt_to |
smtp.data |
|
smtp.queue / smtp.queue_ok |
smtp.queue_msg |
smtp.reset_transaction |
| Metric | Type | Unit | Description |
|---|---|---|---|
haraka.connections |
Counter | Total inbound SMTP connections | |
haraka.hook.total |
Counter | Hook invocations; labeled by haraka.hook |
|
haraka.connection.duration |
Histogram | ms | SMTP connection duration |
haraka.message.size |
Histogram | bytes | Message body size |
haraka.messages |
Counter | Messages by delivery result; labeled by smtp.result (queued, delivered, deferred, bounced) |
|
haraka.up |
Observable Gauge | Always 1 while the plugin is loaded |
See CHANGELOG.md.
Pull requests are welcome. Please open an issue first to discuss significant changes.
Run tests:
npm testCheck code style:
npm run lintAuto-fix style:
npm run formatMIT. See LICENSE.