Email for two-sided marketplaces

Updated

A marketplace sends every event to at least two people with different needs. The buyer wants proof and tracking. The seller wants to know what to ship and when they get paid. Treat them as two audiences from the start.

One event, two emails

| Event | Buyer gets | Seller gets | |---|---|---| | Order placed | Order confirmation | "New order: ship by date" | | Message sent | "New message from the seller" | "New message from a buyer" | | Shipped | Shipping notice | Confirmation of tracking recorded | | Delivered | Review request | "Funds release on date" | | Payout | None | Payout notice with amount and date | | Dispute opened | "We are reviewing your case" | "A buyer opened a dispute: respond by date" | | Refund | Refund confirmation | "An order was refunded" |

Keep contact details private

Do not put either party's address or phone number in the other's email. Send a notification with a link back to the in-product conversation. The Inboxili API cannot set a reply-to address, so a reply to your notification goes to your sending address and not to the other party. Say so in the footer: "Reply in the app, not by email."

Example: new message notification (Node.js)

import { Inboxili } from "@inboxili/node";

const inboxili = new Inboxili({ apiKey: process.env.INBOXILI_API_KEY });
const esc = (s) => String(s).replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);

export async function notifyNewMessage({ message, recipient, sender, thread }) {
  // Throttle: at most one email per thread per recipient every 15 minutes.
  if (!(await redis.set(`msg-mail:${thread.id}:${recipient.id}`, "1", "EX", 900, "NX"))) return;

  await inboxili.emails.send({
    to: recipient.email,
    fromEmail: "messages@yourmarket.example",
    fromName: "Yourmarket",
    subject: "New message about {{item}}",
    htmlBody:
      "<p>{{sender}} sent you a message about <strong>{{item}}</strong>:</p>" +
      "<blockquote>{{preview}}</blockquote>" +
      '<p><a href="{{url}}">Reply in Yourmarket</a>. Replies to this email are not delivered.</p>',
    textBody: `${sender.displayName} sent you a message about ${thread.itemTitle}. Reply in the app: ${thread.url}`,
    templateData: {
      sender: esc(sender.displayName),
      item: esc(thread.itemTitle),
      preview: esc(message.body.slice(0, 160)),
      url: thread.url,
    },
  });
}

The throttle stops an active conversation from sending an email per line.

Things marketplaces get wrong

  • Leaking identity through names, addresses or reply paths.
  • Unescaped user text. Messages and listing titles are user content, and they go into HTML.
  • Email per message. Throttle and digest.
  • Payout notices without a reference. Sellers reconcile against them.
  • Impersonation. Display names are chosen by users. Show the real account link and name together, and never let a user control the sending address.
  • Disputes in email. Keep the evidence in the product. Email only says that something needs attention.

Frequently asked questions

How do I let buyers and sellers talk without sharing addresses?
Keep conversations inside your product and email each side a notification with a link. The Inboxili API has no reply-to field, so replies to the email do not reach the other party anyway.
One email to both parties or two?
Two. Each side needs different content and a different link, and the API takes one recipient per request.

Start sending marketplace email

Create a workspace, verify a domain, and make your first API call.

Related