Skip to main content

Documentation Index

Fetch the complete documentation index at: https://grantmaster.dev/llms.txt

Use this file to discover all available pages before exploring further.

shared/email — API Reference

The shared/email module provides all outbound transactional email capability for GrantMaster, built on Postmark. It exposes a typed template catalogue, a raw send function, a Cloud Function bridge for admin operations, and convenience integration helpers so domain services never need to know Postmark implementation details.

Module Map

FileResponsibility
emailService.tsPostmark client, sendEmail(), sendPostmarkTemplate(), template alias constants
emailIntegration.tsHigh-level integration helpers (invitation, password reset, journal, referral emails)
postmarkAdminService.tsAdmin operations: list/delete suppressions, list messages, webhook management
referralCreditEmails.tsReferral programme transactional emails (award, gift card, launch welcome)

emailService.ts

Environment Variables

VariablePurpose
VITE_POSTMARK_SERVER_TOKENPostmark server API token
VITE_POSTMARK_FROM_EMAILSender address (default: noreply@grantmaster.ai)
VITE_POSTMARK_FROM_NAMESender display name (default: GrantMaster)

sendEmail()

Send a raw HTML/text email.
import { sendEmail } from '@/shared/email/emailService';

await sendEmail(
  'user@example.com',       // to (string or string[])
  'Your report is ready',   // subject
  '<p>HTML body</p>',       // htmlBody
  'Plain text fallback',    // textBody (optional — auto-stripped from HTML)
  {
    cc?: string | string[];
    bcc?: string | string[];
    replyTo?: string;
    tag?: string;           // Postmark message tagging
    metadata?: Record<string, string>;
  }
);
All emails are sent via the outbound message stream with open tracking and HTML-only link tracking enabled.

sendPostmarkTemplate()

Send a Postmark template email by alias.
import { sendPostmarkTemplate, POSTMARK_TEMPLATES } from '@/shared/email/emailService';

await sendPostmarkTemplate(
  'user@example.com',
  POSTMARK_TEMPLATES.JOURNAL_APPROVED,
  {
    user_name: 'Alice',
    journal_period: 'March 2026',
    app_url: 'https://app.grantmaster.ai',
  },
  { tag: 'journal-approved' }
);

POSTMARK_TEMPLATES Catalogue

// User Management
ADMIN_INVITATION           // new org admin setup
USER_INVITATION            // team member invite
PASSWORD_RESET

// Journal Management
JOURNAL_APPROVED
JOURNAL_REJECTED

// Referral Credit System
REFERRAL_CREDIT_AWARDED
REFERRAL_CREDIT_ORG_APPLIED
REFERRAL_CONVERTED
REFERRAL_GIFT_CARD_DELIVERY
REFERRAL_LAUNCH_WELCOME

// Partnership Programme
PARTNER_INVITATION
PARTNER_INVITATION_REMINDER
PARTNER_INVITATION_FINAL_WARNING

// Future / Optional
WELCOME | TRIAL_EXPIRING | TRIAL_EXPIRED | INVOICE | RECEIPT
DUNNING | REFERRAL_INVITATION | SECURITY_ALERT | SCHEDULED_REPORT

emailIntegration.ts

High-level helpers that shield domain services from Postmark details. All helpers resolve the correct app URL and map domain data to Postmark template variables.

Admin Invitation

// Routes through a Firebase Cloud Function to avoid CORS issues
await sendAdminInvitationEmail(
  adminEmail, adminName, organizationName, setupToken, organizationId
);

User Invitation

await sendUserInvitationEmail(
  userEmail, userName, organizationName, role,
  inviteToken, invitationId
);
// Generates: /accept-invitation?id={invitationId}&token={inviteToken}

Password Reset

await sendPasswordResetEmail(email, resetLink);

Journal Notifications

await sendJournalApprovedEmail(userEmail, userName, journalPeriod);
await sendJournalRejectedEmail(userEmail, userName, journalPeriod, rejectionReason);

Partner Invitations

await sendPartnerInvitationEmail(contactEmail, contactName, partnerName, inviteCode, orgName);
await sendPartnerInvitationReminderEmail(contactEmail, contactName, partnerName, inviteCode, daysLeft);
await sendPartnerInvitationFinalWarningEmail(contactEmail, contactName, partnerName, inviteCode);

postmarkAdminService.ts

Provides SuperAdmin-level Postmark account management. Exposes the operations surfaced in src/features/email/ for the Email Management UI panel.

Key Methods

import postmarkAdminService from '@/shared/email/postmarkAdminService';

// Suppressions (bounces, spam complaints, unsubscribes)
postmarkAdminService.getSuppressions(stream?, page?, pageSize?): Promise<SuppressionEntry[]>
postmarkAdminService.deleteSuppressions(addresses: string[]): Promise<DeletionResult>

// Message history
postmarkAdminService.getOutboundMessages(options?): Promise<OutboundMessage[]>
postmarkAdminService.getMessageDetails(messageId): Promise<MessageDetail>

// Webhooks
postmarkAdminService.getWebhooks(): Promise<Webhook[]>
postmarkAdminService.createWebhook(url, events): Promise<Webhook>
postmarkAdminService.deleteWebhook(webhookId): Promise<void>

// Stats
postmarkAdminService.getDeliveryStats(tag?, from?, to?): Promise<DeliveryStats>
postmarkAdminService.getBounceStats(): Promise<BounceStats>

// Templates
postmarkAdminService.listTemplates(): Promise<TemplateSummary[]>
postmarkAdminService.getTemplate(alias): Promise<PostmarkTemplate>

referralCreditEmails.ts

Transactional email helpers specific to the referral credit programme, called by ReferralCreditService.
import {
  sendReferralCreditAwardedEmail,
  sendReferralCreditOrgAppliedEmail,
  sendReferralConvertedEmail,
  sendReferralGiftCardEmail,
  sendReferralLaunchWelcomeEmail,
} from '@/shared/email/referralCreditEmails';

// Credit earned notification
await sendReferralCreditAwardedEmail(userId, amount, totalBalance);

// Org discount applied notification
await sendReferralCreditOrgAppliedEmail(orgId, amount, discountPct);

// Referral converted (referrer notification)
await sendReferralConvertedEmail(referrerId, referredOrgName, creditsEarned);

// Gift card delivery confirmation
await sendReferralGiftCardEmail(recipientEmail, recipientName, giftCardType, amount);

// Programme launch email to all existing users
await sendReferralLaunchWelcomeEmail(userId);

EventBus Events

This module emits no EventBus events. Email sending is triggered directly by domain services and Cloud Functions; failures are logged to Sentry and propagated as thrown errors. Note: There is no dead-letter queue or retry mechanism in the current client-side implementation. Firebase Cloud Functions handle delivery of the admin invitation email; all other templates are sent directly from the client via the Postmark SDK.

Callers

CallerUses
src/features/users/sendUserInvitationEmail(), sendPasswordResetEmail()
src/features/journals/sendJournalApprovedEmail(), sendJournalRejectedEmail()
src/features/partnerships/sendPartnerInvitationEmail() and reminders
src/features/mission/sendReferralCreditAwardedEmail(), sendReferralGiftCardEmail()
src/features/email/postmarkAdminService — Email Management UI
Firebase Cloud FunctionssendAdminInvitation callable (admin invite via Cloud Function)