Invoice and Receipt Emails via API: PDF as a Link, Not an Attachment
Send invoice and receipt emails from your app: gap-free numbering, what a receipt must state, why the PDF should be a link not an attachment, and the API call.
Invoice and receipt emails are legal documents wearing an email costume. They must be numbered, unchangeable, and findable months later, and the way most apps send them (a PDF attached to a plain message) is the way most likely to hit a spam filter or a corporate attachment block. Here is a design that satisfies accountants, spam filters, and your own support team.
Quick answer
Generate the PDF, store it in object storage under an unguessable path, and email a short message whose body contains the essential figures and a link to the PDF. Number invoices sequentially per legal entity with no gaps, never regenerate a sent invoice (issue a credit note instead), and send from billing@ on your own domain with a monitored mailbox behind it.
Why a link beats an attachment
- Attachments from a domain the receiver has not seen before are a classic spam signal. Links to your own domain are not.
- Corporate gateways strip or quarantine PDFs from unknown senders. A link gets through.
- A link can be regenerated with a fresh signature if the storage layout changes; an attachment is frozen in a thousand inboxes.
- The message stays small. A 2 MB PDF times a thousand customers is 2 GB of mail storage you pay for, on both ends.
- You can see downloads in your logs, which is useful when a customer disputes ever receiving the invoice.
Numbering that survives an audit
Most tax authorities require invoice numbers to be sequential and gap-free per issuing entity. Do not use the database primary key (gaps appear when transactions roll back) and do not generate the number in application code with a read-then-increment. Use a database sequence or a single-row counter table updated inside the same transaction that creates the invoice. Prefix with year if you like (2026-000482) but never reuse a number, and never change a number after the email has gone out. Receipts, which record a payment rather than request one, can use the payment processor's id as the reference.
What the email body must state
- Invoice or receipt number, and which of the two it is.
- Issue date and, for invoices, the due date and accepted payment methods.
- Amount with currency code, tax amount and rate, and total.
- Your legal name, address, and tax registration number. Many countries require these on the document and it does no harm in the email.
- The customer name and billing address as they will appear on the PDF.
- The download link, and a sentence saying how long it remains valid.
The send request
The link is a signed URL that expires in, say, 90 days; after that the customer can fetch it again from their account page.
curl -X POST https://api.oqumail.com/api/v1/emails \
-H "Authorization: Bearer $OQUMAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"from":"billing@yourdomain.com","to":"accounts@customer.example","subject":"Invoice 2026-000482 from Acme Ltd (USD 1,200.00, due 15 Aug)","html":"<p>Invoice <strong>2026-000482</strong> for <strong>USD 1,200.00</strong> (incl. VAT 200.00) is due on 15 Aug 2026.</p><p><a href=\"https://app.yourdomain.com/invoices/2026-000482.pdf?sig=abc123\">Download PDF</a> (link valid 90 days)</p><p>Acme Ltd, 1 Example Street, Nairobi. VAT no. P051234567X.</p>","text":"Invoice 2026-000482 for USD 1,200.00 (incl. VAT 200.00) is due 15 Aug 2026. Download: https://app.yourdomain.com/invoices/2026-000482.pdf?sig=abc123"}'Implementation steps
- On payment (receipt) or on order completion for pay-later customers (invoice), open a transaction, claim the next number, write the invoice row, commit.
- Render the PDF from the frozen invoice row, never from live product data. Store it with the number in the filename.
- Store the object path and a SHA-256 of the file so you can prove it has not changed.
- Enqueue the send with a signed link. If the send fails, retry the send; never regenerate the PDF or the number.
- Record the API message id on the invoice so support can pull the delivery log.
- Expose all invoices on the customer account page. Emails get lost; account pages do not.
Sending from the right place
B2B customers often route invoices to a shared accounts@ mailbox with strict filters, so authentication matters more than usual. Send from billing@ on your verified domain with SPF, DKIM and DMARC in place, and keep billing@ as a real mailbox so "please resend invoice 482" and remittance advices land with a person. OquMail gives you the API and the mailbox on the same free plan, with the DNS records set up under guidance and a delivery log that shows the exact SMTP response from the customer's mail server when accounts payable claims they never received it.
Common questions
Do I ever need to attach the PDF?
Some large customers insist on it for their AP automation. Offer it as a per-customer setting rather than the default, and still include the link in the body.
What if I need to correct an invoice?
Issue a credit note that references the original number, then a new invoice. Editing an issued invoice breaks the audit trail and, in many countries, the law.
Should receipts and invoices be different emails?
Yes. A receipt confirms money received; an invoice requests it. Mixing the two ("Invoice / Receipt") confuses accountants, who file them differently.
Free business email on your own domain
OquMail gives you up to 15 mailboxes on your domain — free — with guided SPF/DKIM/DMARC, webmail, IMAP/SMTP for any mail app, and a send API. Most teams are live in under fifteen minutes. Start at oqumail.com.
Get started free