Vacation Auto-Responder (F4.7) β
Feature: F4.7 β Vacation Auto-Responder Status: π’ COMPLETED Package:
@vexlyx/api,@vexlyx/dashboard,@vexlyx/sharedDepends on: F4.1 (Postfix SMTP), F4.2 (Dovecot IMAP), F4.3 (Mailbox Management UI) Protocols: RFC 5228 (Sieve), RFC 5230 (Vacation Extension), RFC 5260 (Date & Index Extensions), LMTP
1. Overview β
F4.7 introduces automated "out-of-office" vacation responders per mailbox. When active, incoming mail delivered to a mailbox automatically triggers an auto-reply to the original sender, rate-limited to once per sender within a configurable repeat interval (1β30 days), while keeping normal inbox delivery completely intact.
Key Capabilities β
- Pigeonhole Sieve Processing: Dovecot's Pigeonhole Sieve engine compiles and executes server-side Sieve scripts on incoming delivery.
- Postfix -> Dovecot LMTP Delivery: Mail delivery is handed off from Postfix to Dovecot via LMTP (
lmtp:dovecot:24), enabling per-user Sieve script execution and automated response generation. - DKIM-Signed Auto-Replies: Dovecot's Sieve vacation action relays outgoing replies back to Postfix (
submission_host = postfix:25), ensuring all auto-replies are DKIM-signed and properly authenticated before dispatch. - Rate-Limiting & Duplicate Suppression: The
:daysparameter suppresses duplicate replies to the same sender within the specified interval, tracked in Dovecot's duplicate database. - Optional Date Windows: Support for scheduled vacation periods using Sieve's RFC 5260
dateandrelationalextensions, active only within the specified date boundaries. - Per-Mailbox UI: Tactile modal on the mailboxes table with instant status badge feedback.
2. Architecture & Data Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js Dashboard UI β
β /mail β MailboxesPanel.tsx β
β - "Auto-reply" badge on active mailboxes β
β - Palmtree action icon β VacationResponderDialog.tsx β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β HTTP / JSON
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Fastify API Server β
β GET /api/mailboxes/:id/vacation β
β PUT /api/mailboxes/:id/vacation β
βββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββ
β PostgreSQL (Prisma) β β system/python/ β
β model VacationResponder β β dovecot_manager.py β
β - mailboxId (unique) β β - sync_vacation β
β - enabled, subject, message β β - generate_sieve_script β
β - intervalDays, dates β βββββββββββββββ¬ββββββββββββββ
βββββββββββββββββββββββββββββββββ β Writes
βΌ
/var/mail/vhosts/<domain>/<user>/.dovecot.sieve
β
βΌ
ββββββββββββββββββββ LMTP:24 ββββββββββββββββββββ
β vexlyx-postfix ββββββββββββββββββββββββββββββΆβ vexlyx-dovecot β
β (Port 25/587) β β (IMAP + LMTP) β
β βββββββββββββββββββββββββββββββ Pigeonhole runs β
ββββββββββββββββββββ SMTP:25 (submission) β .dovecot.sieve β
(signs with DKIM) ββββββββββ¬ββββββββββ
β Stores message
βΌ
/var/mail/vhosts/.../Maildir3. Configuration Specifications β
1. Dovecot LMTP & Sieve Configuration (docker/dovecot/dovecot.conf) β
protocols = imap lmtp- LMTP TCP Listener on Port 24:text
service lmtp { inet_listener lmtp { port = 24 } } - Sieve Mail Plugin in LMTP:text
protocol lmtp { mail_plugins = $mail_plugins sieve } - Pigeonhole Plugin & Submission Relay:text
plugin { quota = maildir:User quota sieve = /var/mail/vhosts/%d/%n/.dovecot.sieve sieve_default = /var/mail/vhosts/%d/%n/.dovecot.sieve sieve_vacation_send_from_recipient = yes } submission_host = postfix:25
2. Postfix Virtual Transport (docker/postfix/main.cf) β
Postfix routes virtual mailboxes to Dovecot LMTP:
virtual_transport = lmtp:dovecot:24Recipient addresses are verified against virtual_mailbox_maps and virtual_domains before LMTP handoff, preventing open backscatter.
3. Docker Container (docker/dovecot/Dockerfile) β
Installs dovecot-lmtpd and dovecot-pigeonhole-plugin on Alpine Linux, exposing port 24:
RUN apk add --no-cache \
dovecot \
dovecot-lmtpd \
dovecot-pigeonhole-plugin \
openssl \
ca-certificates \
bash
EXPOSE 143 993 24 123454. Sieve Script Generation β
Generated scripts strictly follow RFC 5228, RFC 5230, and RFC 5260:
Standard Script β
require ["vacation"];
vacation
:days 7
:subject "Out of office: Vacation"
text:
I am currently away with limited access to email.
.
;Scheduled Date Window Script β
require ["vacation", "date", "relational"];
if allof (
currentdate :value "ge" "date" "2026-10-01",
currentdate :value "le" "date" "2026-10-15"
) {
vacation
:days 1
:subject "Out of office"
text:
I am away from Oct 1 to Oct 15.
.
;
}- When
enabled=false,dovecot_manager.pyremoves.dovecot.sieveand.dovecot.svbin. - Script files use strict LF (
\n) newlines to prevent Windows line-ending corruption in Linux containers.
5. API Endpoints β
All endpoints require session authentication (app.requireAuth).
GET /api/mailboxes/:id/vacation β
Returns the vacation responder configuration for a mailbox. If none exists, returns default inactive configuration.
Response:
{
"responder": {
"id": "cuid...",
"mailboxId": "cuid...",
"enabled": true,
"subject": "Out of office: Auto-reply",
"message": "Away on leave.",
"intervalDays": 1,
"startDate": "2026-10-01T00:00:00.000Z",
"endDate": "2026-10-15T00:00:00.000Z",
"createdAt": "2026-09-06T05:50:00.000Z",
"updatedAt": "2026-09-06T05:55:00.000Z"
}
}PUT /api/mailboxes/:id/vacation β
Upserts the vacation responder configuration in PostgreSQL and synchronizes the .dovecot.sieve script on disk.
Request Body:
{
"enabled": true,
"subject": "Out of office: Vacation",
"message": "I will respond upon my return.",
"intervalDays": 3,
"startDate": "2026-10-01T00:00:00.000Z",
"endDate": "2026-10-15T00:00:00.000Z"
}6. How to Test β
Automated Tests β
Run the dedicated test suite:
python -m unittest tests.test_vacation_responder -vTests verify:
- Sieve script generation syntax and dot-stuffing.
- Enabling/disabling script persistence on disk.
- Date condition inclusion (RFC 5260).
- Configuration syntax for Dovecot LMTP, Pigeonhole, and Postfix routing.
- Fastify API route authentication enforcement (401).
Full Mail Subsystem Test Run β
python -m unittest tests.test_vacation_responder tests.test_dovecot_imap tests.test_postfix_smtp -v7. How to Extend β
- Custom Sieve Rules: The current implementation uses Sieve's
vacationaction. This can be extended in future phases to support custom server-side filter rules (e.g. forward to another address or move spam to Junk folder) by adding more action blocks to.dovecot.sieve. - ManageSieve Protocol: For power users or third-party webmail clients, ManageSieve (port 4190) can be exposed in Dovecot by installing
dovecot-managesieved.