Deadman Vault sends automated email notifications at every critical lifecycle transition — from the first warning that a vault is nearing its deadline, through the grace period countdown, all the way to per-beneficiary payout confirmations with Stacks explorer links. The email system is built on Resend and is designed to fail gracefully: ifDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/natureloved/DeadMan-Vault/llms.txt
Use this file to discover all available pages before exploring further.
RESEND_API_KEY or RESEND_FROM_EMAIL are missing, all notification functions silently no-op and vault operations proceed normally. Emails are informational — funds are transferred regardless of whether email delivery succeeds.
Setup
Create a Resend account
Sign up at resend.com and generate an API key from your dashboard.
Verify a sender domain
In your Resend dashboard, add and verify the domain you’ll send from.
RESEND_FROM_EMAIL must use a verified domain — for example, noreply@yourdomain.com. Resend will reject sends from unverified domains.Low-Level Primitive: sendEmail()
All notification functions call sendEmail() internally. It is the only function that directly invokes the Resend SDK:
Deduplication
Warning and grace-period emails are deduplicated to prevent spamming the owner during the keeper cron’s frequent sweeps. The deduplication mechanism lives insrc/lib/supabase/queries.ts:
hasRecentNotification(vaultId, type, hours). If a notification of the same type was already sent for that vault within the dedup window, the send is skipped. Each sent notification is recorded in the notifications table via addNotification().
Notification Functions
sendWarningEmail(vault, ownerEmail)
Sent to the vault owner when the vault status transitions to "warning" — triggered when the remaining blocks until deadline fall to 432 blocks or fewer (approximately 3 days on Stacks mainnet cadence).
- Recipient: vault owner
- Subject:
⚠️ Deadman Vault — Check In Before It's Too Late - Trigger condition:
deadlineBlock - currentBlock <= 432(≈ 3 days) - Deduplication: once per 24 hours per vault
- Body: includes vault name and a direct link to the heartbeat check-in page
sendGracePeriodEmail(vault, ownerEmail)
Sent to the vault owner when the vault enters "grace_period" status — the 48-hour window after the heartbeat deadline passes but before the vault fully triggers.
- Recipient: vault owner
- Subject:
🚨 Deadman Vault — 48 Hour Grace Period - Trigger condition: vault status is
"grace_period" - Deduplication: once per 48 hours per vault
- Body: includes vault name and an urgent check-in link
sendClaimReadyEmail(beneficiary, vault)
Sent to each beneficiary the moment a vault flatlines and triggers. This is a heads-up notification — it tells the beneficiary they’ve been named and what to expect. If vesting is configured (vesting_days > 0), the email shows the vesting_release_at date and explains that funds will be sent automatically at that time. Silently no-ops if the beneficiary has no email field.
- Recipient: each beneficiary (individually)
- Subject:
💰 Deadman Vault — You've Been Named a Beneficiary - Trigger condition: vault status transitions to
"triggered" - Deduplication: none (sent exactly once per beneficiary per trigger)
- Vesting awareness: if
vesting_release_atis in the future, the email shows the release date; otherwise it confirms funds are being sent immediately - No email, no problem: beneficiaries without an
emailfield still receive their funds — the on-chain transfer happens regardless
sendFundsReleasedEmail(beneficiary, vault, amount, txId)
Sent to a beneficiary after their token transfer has been confirmed on-chain. Includes the exact amount transferred, the beneficiary’s wallet address, and a direct link to the transaction on the Stacks testnet explorer.
- Recipient: each beneficiary (individually, after their specific transfer confirms)
- Subject:
✅ Deadman Vault — Funds Sent to Your Wallet - Trigger condition:
sendTokenTransfer()succeeds insettleVaultPayout() - Deduplication: none (called exactly once per successful transfer)
- Explorer link:
https://explorer.stacks.co/txid/{txId}?chain=testnet - Amount: passed as a human-readable token string (e.g.,
"12.50") viamicroToToken()from the FlowVault SDK
Notification Events Reference
| Event | Recipient | Trigger Condition | Dedup Window |
|---|---|---|---|
sendWarningEmail | Vault owner | deadlineBlock - currentBlock <= 432 | 24 hours |
sendGracePeriodEmail | Vault owner | Vault enters grace_period status | 48 hours |
sendClaimReadyEmail | Each beneficiary | Vault transitions to triggered | None (once per trigger) |
sendFundsReleasedEmail | Each beneficiary | On-chain transfer confirmed in settlement | None (once per transfer) |
Notifications Table Schema
Thenotifications table records every sent email and is used exclusively for deduplication lookups:
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
vault_id | uuid | Foreign key to the vault |
type | text | Notification type key (e.g., "warning", "grace_period") |
recipient_email | text | Email address the notification was sent to (optional) |
recipient_address | text | Stacks address of the recipient (optional) |
status | text | Delivery status of the notification |
sent_at | timestamptz | Timestamp of when the notification was recorded |
The
notifications table is protected by the same RLS policy as all other tables — zero public access, service-role key only. Deduplication queries run server-side in the keeper cron.