Summary
The "Send" button on invoices currently only flips the invoice status from draft → sent and records a sent_at timestamp. No email is actually delivered to the customer.
invoice_service.mark_sent() (invoice_service.py:345) is the entry point — it needs email dispatch wired in.
What needs to be built
Backend
- SMTP configuration in
CompanySettings (host, port, username, password, from-address) or env-var based config
- Transactional email service (send via SMTP or a provider like SendGrid / Resend / Postmark)
send_invoice_email(db, invoice_id) function in invoice_service.py:
- Generate the PDF (already works via
generate_invoice_pdf)
- Attach it to an email addressed to
invoice.customer_email
- Send with subject line e.g.
"Invoice {invoice_number} from {company_name}"
- Record delivery attempt / result on the invoice record (add
last_email_sent_at, optionally email_delivery_status)
- The
/invoices/{id}/send endpoint should call this instead of just mark_sent
Frontend
- Show a spinner / success toast after clicking "Send" so the user knows it fired
- If
customer_email is missing, prompt before sending or show a clear error
Settings
- Add SMTP / email provider config section to Admin Settings (host, port, from-name, from-email, username, password)
- "Test connection" button to verify credentials before saving
Out of scope
- Email tracking (open/click pixels) — future
- Customer portal email threads — future
- Bulk send — future
Notes
- PDF generation is already solid (ReportLab,
generate_invoice_pdf). This is purely a delivery layer.
mark_sent status transition logic should stay — it just needs email dispatch added before or alongside it.
- If SMTP is not configured, "Send" should either be disabled or warn the user rather than silently doing nothing.
Summary
The "Send" button on invoices currently only flips the invoice status from
draft→sentand records asent_attimestamp. No email is actually delivered to the customer.invoice_service.mark_sent()(invoice_service.py:345) is the entry point — it needs email dispatch wired in.What needs to be built
Backend
CompanySettings(host, port, username, password, from-address) or env-var based configsend_invoice_email(db, invoice_id)function ininvoice_service.py:generate_invoice_pdf)invoice.customer_email"Invoice {invoice_number} from {company_name}"last_email_sent_at, optionallyemail_delivery_status)/invoices/{id}/sendendpoint should call this instead of justmark_sentFrontend
customer_emailis missing, prompt before sending or show a clear errorSettings
Out of scope
Notes
generate_invoice_pdf). This is purely a delivery layer.mark_sentstatus transition logic should stay — it just needs email dispatch added before or alongside it.