Abandoned Cart Emails from Your Own App: Timing, Consent, and Sending
Build abandoned cart emails in your own code: when to send, how many, what consent you need, the content that recovers carts, and the send API request.
Abandoned cart emails are one of the few automated messages with a directly measurable return, which is why every shop platform sells an add-on for them. If you run your own checkout you can build the sequence in an afternoon, but two details decide whether it works: sending at the right moment, and having the right to send it at all. Both are covered below, with the request that sends the email.
Quick answer
Send the first reminder about 1 hour after the cart goes idle, a second at 24 hours, and stop. Only email people who gave you their address in this session and did not opt out, and treat the email as marketing, which means an unsubscribe link and your postal address in the footer. Send it from a warm, authenticated domain and from a background job, and stop the sequence the moment the order completes.
Is this email allowed?
An abandoned cart email is marketing, not a transactional message, because the customer has not bought anything. In the EU and UK you need either consent or the "soft opt-in" (an existing customer, similar goods, an easy opt-out in every message, and the address collected during a sale or negotiations for one). A first-time visitor who typed an email into the checkout and left is a grey area; many shops only send when the visitor is a logged-in customer or ticked a marketing box. In the US, CAN-SPAM allows it with a working unsubscribe and a postal address. In Canada, CASL requires consent, express or implied. Read your local rule before you write the job.
Capturing the cart
- Persist the cart server-side as soon as the email field is filled, not only at "Place order". Use a debounce on the email input and save on blur.
- Record consent state: marketing_opt_in true/false, and whether the person is an existing customer.
- Record last_activity_at on every cart change.
- Run a scheduler every 10 minutes that selects carts with last_activity_at older than 60 minutes, no order, no reminder sent, and allowed to email.
- Enqueue the send, then set reminder_1_sent_at. Repeat for reminder 2 at 24 hours.
- On order creation, mark the cart converted so the scheduler skips it.
The content that recovers carts
- Subject: plain and specific, "You left 2 items in your cart", not "Come back!!!".
- Show the items with images, names, and prices. The email should look like the cart.
- One button: "Return to your cart", linking to a URL that restores the cart by a signed token, not by requiring login.
- A line about shipping cost or free shipping threshold, since that is the number one reason for abandonment.
- A real reply address for questions about sizing or stock.
- A discount only in the second email, if at all. Offering it in the first teaches people to abandon on purpose.
- An unsubscribe link and your business address in the footer.
The send request
const res = await fetch("https://api.oqumail.com/api/v1/emails", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.OQUMAIL_API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({
from: "hello@yourdomain.com",
to: cart.email,
subject: "You left " + cart.items.length + " items in your cart",
html: renderCartHtml(cart, restoreUrl) + '<p style="font-size:12px;color:#666">Sent because you started a checkout at Acme. <a href="' + unsubscribeUrl + '">Unsubscribe</a>. Acme Ltd, 1 Example Street, Nairobi.</p>',
text: "You left " + cart.items.length + " items in your cart. Return: " + restoreUrl + "\nUnsubscribe: " + unsubscribeUrl
})
});
if (!res.ok) throw new Error("send failed: " + res.status);Timing details that matter
One hour is the sweet spot for the first message: long enough that the customer has genuinely left, short enough that the intent is still warm. Do not send within 15 minutes; many people are still comparing tabs. Respect the customer's local night: if the 60-minute mark falls between 22:00 and 08:00, hold the email until morning. Cap the sequence at two messages; a third produces unsubscribes and complaints, and complaints above roughly 0.3% are what get a domain throttled by Gmail and Yahoo.
Domain and reputation
Because this is marketing-flavoured mail, it needs a clean sending identity more than a receipt does. Send from your shop's own domain with SPF, DKIM and DMARC passing, keep it on the same domain as your order confirmations so the reputation is shared, and keep the volume steady. OquMail sets up those records with live DNS checks when you add the domain and gives you a delivery log per message, so if recovery emails start deferring you will see the SMTP responses rather than guessing. Keep the free plan's fair-use limits in mind: cart reminders are low volume by nature, which is fine, but do not bolt a newsletter blast onto the same key.
Common questions
How many abandoned cart emails should I send?
Two. One at about an hour, one the next day. The first email does most of the work and a third adds complaints faster than orders.
Should I include a discount code?
Only in the second email, only for first-time customers, and only if your margin allows it. Repeat customers learn to abandon carts to trigger the code.
Can I send abandoned cart emails to guests?
Only if they consented or your jurisdiction's soft opt-in applies. The safest pattern is a small checkbox next to the email field: "Email me if I leave items in my cart." Unchecked means no email.
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