Les plateformes de marketplace font face à des défis e-mail uniques : plusieurs parties, des flux de transaction complexes et la nécessité d’instaurer la confiance entre inconnus. Voici comment concevoir des systèmes de notifications multipartites efficaces.
Le défi e-mail des marketplaces
Contrairement aux applications mono-partie, les marketplaces doivent communiquer avec :
- —Des acheteurs qui effectuent des achats
- —Des vendeurs qui exécutent les commandes
- —La plateforme elle-même (litiges, politiques, etc.)
Chaque partie a besoin d’informations différentes à des moments différents, et les e-mails doivent inspirer confiance tout en protégeant la vie privée.
Types de notifications principaux
E-mails du cycle de vie de la commande
À l'acheteur :
Order confirmed → Payment processed → Shipped → Delivered → Review request
Au vendeur :
New order → Payment received → Ship reminder → Delivery confirmed → Payout processed
Exemple : Confirmation de commande (acheteur)
interface BuyerOrderEmail {
buyer: {
name: string;
email: string;
};
order: {
id: string;
items: OrderItem[];
total: number;
estimatedDelivery: string;
};
seller: {
storeName: string;
// Note: No seller email or personal details
};
}
const buyerOrderTemplate = `
Hi {{buyer.name}},
Your order #{{order.id}} is confirmed!
Items from {{seller.storeName}}:
{{#each order.items}}
- {{this.name}} × {{this.quantity}}: ${{this.price}}
{{/each}}
Total: ${{order.total}}
Estimated delivery: {{order.estimatedDelivery}}
Track your order: {{trackingUrl}}
`;
Exemple : Nouvelle commande (vendeur)
interface SellerOrderEmail {
seller: {
name: string;
email: string;
};
order: {
id: string;
items: OrderItem[];
revenue: number;
platformFee: number;
payout: number;
shippingAddress: Address;
shipBy: string;
};
buyer: {
// Only what seller needs
shippingName: string;
};
}
const sellerOrderTemplate = `
Hi {{seller.name}},
New order #{{order.id}}!
Items to ship:
{{#each order.items}}
- {{this.name}} × {{this.quantity}}
{{/each}}
Ship to:
{{buyer.shippingName}}
{{order.shippingAddress.line1}}
{{order.shippingAddress.city}}, {{order.shippingAddress.state}} {{order.shippingAddress.zip}}
Ship by: {{order.shipBy}}
Revenue: ${{order.revenue}}
Platform fee: -${{order.platformFee}}
Your payout: ${{order.payout}}
`;
Communication respectueuse de la confidentialité
Les marketplaces doivent souvent faciliter la communication entre acheteurs et vendeurs sans exposer les e-mails personnels.
Relais d’e-mails masqués
// Generate masked addresses
function createMaskedEmail(orderId: string, party: 'buyer' | 'seller'): string {
const token = generateSecureToken(orderId, party);
return `${token}@relay.marketplace.com`;
}
// When buyer wants to contact seller
const buyerMaskedEmail = createMaskedEmail(order.id, 'buyer');
// [email protected]
// When seller wants to contact buyer
const sellerMaskedEmail = createMaskedEmail(order.id, 'seller');
// [email protected]
Gestion du relais
// Inbound email handler
async function handleRelayEmail(inbound: InboundEmail) {
const { token, party } = parseRelayAddress(inbound.to);
const order = await getOrderByToken(token);
if (!order) {
return sendBounce(inbound.from, 'Invalid relay address');
}
// Determine recipient
const recipient = party === 'buyer'
? order.seller.email
: order.buyer.email;
// Forward with masked reply-to
await sendEmail({
to: recipient,
from: '[email protected]',
replyTo: inbound.to, // Keep the relay address
subject: `Re: Order #${order.id} - ${inbound.subject}`,
html: sanitizeHtml(inbound.html),
headers: {
'X-Marketplace-Order': order.id,
'X-Marketplace-Thread': inbound.headers['message-id']
}
});
// Log for dispute resolution
await logMessage({
orderId: order.id,
from: party === 'buyer' ? 'seller' : 'buyer',
content: inbound.text,
timestamp: new Date()
});
}
E-mails de transaction multipartites
Séquestre et flux de paiement
// Payment held in escrow
await sendEmail({
to: buyer.email,
template: 'payment-held',
data: {
amount: order.total,
releaseCondition: 'Funds will be released to seller upon delivery confirmation'
}
});
await sendEmail({
to: seller.email,
template: 'payment-pending',
data: {
amount: order.payout,
releaseCondition: 'Ship within 3 days to receive payment'
}
});
// After delivery confirmed
await sendEmail({
to: seller.email,
template: 'payment-released',
data: {
amount: order.payout,
arrivalDate: calculatePayoutDate()
}
});
Notifications de litige
interface DisputeEmail {
disputeId: string;
orderId: string;
reason: string;
filedBy: 'buyer' | 'seller';
deadline: string;
}
// Notify both parties
async function notifyDispute(dispute: DisputeEmail) {
const order = await getOrder(dispute.orderId);
// To the party who filed
await sendEmail({
to: dispute.filedBy === 'buyer' ? order.buyer.email : order.seller.email,
template: 'dispute-filed-confirmation',
data: {
disputeId: dispute.disputeId,
nextSteps: 'We\'ll review and respond within 48 hours'
}
});
// To the other party
await sendEmail({
to: dispute.filedBy === 'buyer' ? order.seller.email : order.buyer.email,
template: 'dispute-notification',
data: {
disputeId: dispute.disputeId,
reason: dispute.reason,
deadline: dispute.deadline,
responseUrl: `${baseUrl}/disputes/${dispute.disputeId}/respond`
}
});
}
E-mails d’intégration des vendeurs
Parcours de vérification
const sellerOnboardingSequence = [
{
trigger: 'signup',
delay: 0,
template: 'seller-welcome',
data: { nextStep: 'Verify your identity' }
},
{
trigger: 'identity-submitted',
delay: 0,
template: 'identity-review',
data: { reviewTime: '1-2 business days' }
},
{
trigger: 'identity-approved',
delay: 0,
template: 'identity-approved',
data: { nextStep: 'Add your first listing' }
},
{
trigger: 'first-listing',
delay: 0,
template: 'listing-live',
data: { tips: 'Optimize your listing for search' }
},
{
trigger: 'first-sale',
delay: 0,
template: 'first-sale-congrats',
data: { payoutInfo: true }
}
];
Notifications de versement
// Weekly payout summary
await sendEmail({
to: seller.email,
template: 'payout-summary',
data: {
period: 'Dec 23-29, 2025',
orders: 12,
grossRevenue: 1250.00,
platformFees: 125.00,
refunds: 45.00,
netPayout: 1080.00,
payoutDate: 'Dec 31, 2025',
payoutMethod: 'Bank account ending in 4242'
}
});
Communications de la plateforme
Mises à jour des politiques
// Segment by user type
async function sendPolicyUpdate(policy: PolicyUpdate) {
const affectedUsers = await getUsersByType(policy.affectsUserTypes);
for (const user of affectedUsers) {
await sendEmail({
to: user.email,
template: 'policy-update',
data: {
policyName: policy.name,
effectiveDate: policy.effectiveDate,
summary: policy.summary,
// Customize based on user type
impact: policy.impactByUserType[user.type],
actionRequired: policy.actionRequired[user.type]
}
});
}
}
Confiance et sécurité
// Account warning
await sendEmail({
to: user.email,
template: 'account-warning',
data: {
violation: 'Policy violation detected',
details: 'Your listing "XYZ" was removed for...',
consequence: 'This is your first warning',
appealUrl: `${baseUrl}/appeals/new`
}
});
// Account suspension
await sendEmail({
to: user.email,
template: 'account-suspended',
data: {
reason: 'Multiple policy violations',
pendingOrders: 'Active orders will be cancelled and refunded',
pendingPayouts: 'Payouts are on hold pending review',
appealDeadline: '14 days',
appealUrl: `${baseUrl}/appeals/new`
}
});
E-mails d’avis et de notation
Moment d’envoi de la demande d’avis
// Request review after confirmed delivery
async function scheduleReviewRequest(order: Order) {
const deliveryDate = order.deliveredAt;
// Wait 2 days after delivery
await scheduleEmail({
sendAt: addDays(deliveryDate, 2),
to: order.buyer.email,
template: 'review-request',
data: {
orderId: order.id,
sellerName: order.seller.storeName,
items: order.items,
reviewUrl: `${baseUrl}/orders/${order.id}/review`
}
});
}
Notification d’avis au vendeur
await sendEmail({
to: seller.email,
template: 'new-review',
data: {
rating: 5,
reviewText: 'Great product, fast shipping!',
orderDate: 'Dec 15, 2025',
// Don't include buyer name for privacy
responseUrl: `${baseUrl}/reviews/${review.id}/respond`
}
});
Architecture e-mail pour l’échelle
Notifications pilotées par les événements
// Central event handler
async function handleMarketplaceEvent(event: MarketplaceEvent) {
const notifications = getNotificationsForEvent(event.type);
for (const notification of notifications) {
const recipients = await getRecipients(event, notification.recipientType);
for (const recipient of recipients) {
await queueEmail({
to: recipient.email,
template: notification.template,
data: await buildTemplateData(event, recipient, notification),
priority: notification.priority
});
}
}
}
// Event types
type MarketplaceEvent =
| { type: 'order.created'; order: Order }
| { type: 'order.shipped'; order: Order; tracking: TrackingInfo }
| { type: 'order.delivered'; order: Order }
| { type: 'dispute.opened'; dispute: Dispute }
| { type: 'payout.processed'; payout: Payout }
| { type: 'review.submitted'; review: Review };
Préférences de notification
interface MarketplaceNotificationPrefs {
// Buyer preferences
orderUpdates: boolean; // Can't disable
shippingUpdates: boolean; // Can't disable
promotions: boolean; // Can disable
reviewReminders: boolean; // Can disable
// Seller preferences
newOrders: boolean; // Can't disable
payoutNotifications: boolean; // Can't disable
performanceReports: boolean; // Can disable
sellerTips: boolean; // Can disable
}
Bonnes pratiques
- —Protéger la confidentialité - Ne jamais exposer les coordonnées personnelles entre les parties
- —Identité de l’expéditeur claire - Il doit être évident que les e-mails proviennent de la plateforme
- —Contenu actionnable - Chaque e-mail doit proposer une prochaine étape claire
- —Calendrier cohérent - Définir des attentes sur le moment d’arrivée des e-mails
- —Piste d’audit - Journaliser toutes les communications pour la résolution des litiges
- —Respect des préférences - Permettre de désactiver les notifications non essentielles
L’e-mail en marketplace consiste à instaurer la confiance entre inconnus tout en protégeant les intérêts de chacun. Concevez vos notifications pour informer, protéger et faciliter des transactions fluides.