Developer tutorial: Building end-to-end encrypted document notifications using RCS with email fallback
developermobilesecurity

Developer tutorial: Building end-to-end encrypted document notifications using RCS with email fallback

UUnknown
2026-02-13
11 min read
Advertisement

Tutorial: Build E2EE RCS document approvals with automated email fallback for secure, auditable approvals.

Hook: Stop chasing approvals in inboxes — secure, realtime approvals where users already are

Disorganized approvals, lost documents and long turnaround times cost small businesses real money. Mobile messaging (RCS) finally gives business workflows a modern, interactive channel — but security and universal reach remain top concerns. In this tutorial you’ll learn how to build an end-to-end encrypted RCS document notification flow for approvals, with an automatic, auditable email fallback so nothing stalls when RCS isn’t available.

Why this matters in 2026

RCS adoption accelerated in 2024–2026 with the GSMA Universal Profile enhancements and major OS vendors gradually adding E2EE support. Apple’s iOS betas in late 2025/early 2026 show movement toward RCS E2EE, and major messaging vendors updated specs to support MLS-style key management. At the same time Google’s 2026 updates to Gmail and platform AI features have increased the prominence of privacy-first channels — making E2EE for mobile approvals a practical priority.

What you’ll build (overview)

  • A server-side notification service that sends approval requests over RCS when available
  • Per-recipient end-to-end encryption of the approval payload (link + metadata)
  • Automated fallback to signed, TLS-delivered email if RCS is unavailable
  • An auditable webhook endpoint that verifies signer identity and preserves an immutable approval trail

Architecture & components

Keep the design simple and modular. You’ll need these components:

  • Notification Coordinator — server logic that decides channel (RCS vs email) and orchestrates encryption, token creation and retries.
  • Key Management — a safe store for client public keys and your server keys (KMS or HSM).
  • RCS Provider Adapter — integrates with your RCS messaging vendor (e.g., Twilio, Vonage, Google Business Messaging or direct telco partners).
  • Email Adapter — SMTP/SendGrid/AWS SES client for fallback.
  • Document Store — where documents live; host approvals via short-lived, single-use URLs.
  • Webhook/Approval Processor — receives approval callbacks and creates audit records.

Key design decisions

  1. Encrypt the sensitive payload before handing it to any provider. Even if the RCS channel offers E2EE in the wild, encrypting end-to-end ensures consistent privacy and simplifies compliance.
  2. Use short-lived, single-use approval tokens to limit replay attacks.
  3. Store only hashes of approvals in your audit logs (not the raw payload) unless needed for compliance.
  4. Keep email fallback signed and TLS-encrypted and prefer S/MIME or PGP for PHI or regulated documents.

Step 1 — User onboarding and key discovery

To enable E2EE you must collect or discover a recipient public key. There are three practical approaches:

  • Client-generated public keys: the mobile app or JS client generates a long-lived key pair during onboarding and uploads the public key to your API.
  • Provider-assisted discovery: query an RCS capability API (if your provider exposes user device keys or a key identifier). This is still emerging as of 2026 and varies by vendor.
  • Fallback to server-wrapped encryption: for recipients without a public key, encrypt the payload with an ephemeral symmetric key and deliver that key via a secure email or SMS OTP (less ideal).

Best practice in 2026: prefer client-generated keys bound to a user identity and rotate them periodically. Store public keys in a neutral key directory protected by your KMS.

Step 2 — Payload design

Keep the RCS message minimal. Don’t send entire documents through RCS. Instead provide:

  • Reference to the document (document id)
  • Approval action metadata (requester, amount, due date)
  • Short-lived approval URL (single-use, nonce), encrypted
  • Signature over the payload (server-signed JWT or detached signature)

Step 3 — Implementing end-to-end encryption (Node.js example)

This implementation uses X25519 ECDH to derive a shared secret and AES-GCM for payload encryption. Node 20+ supports X25519 keypairs natively.

// Node.js example (server-side)
const crypto = require('crypto');

function encryptForRecipient(recipientPubKeyBase64, plaintext) {
  // recipientPubKeyBase64 is the recipient's X25519 public key (base64)
  const recipientPub = Buffer.from(recipientPubKeyBase64, 'base64');

  // server ephemeral key
  const serverKey = crypto.generateKeyPairSync('x25519');
  const serverPriv = serverKey.privateKey.export({ type: 'pkcs8', format: 'der' });
  const serverPub = serverKey.publicKey.export({ type: 'spki', format: 'der' });

  // derive shared secret
  const shared = crypto.diffieHellman({
    privateKey: serverKey.privateKey,
    publicKey: crypto.createPublicKey({ key: recipientPub, type: 'spki', format: 'der' })
  });

  // derive symmetric key
  const hkdf = crypto.createHmac('sha256', Buffer.alloc(32));
  hkdf.update(shared);
  const symKey = hkdf.digest().slice(0, 32);

  // encrypt with AES-GCM
  const iv = crypto.randomBytes(12);
  const cipher = crypto.createCipheriv('aes-256-gcm', symKey, iv);
  const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
  const tag = cipher.getAuthTag();

  return {
    serverPubBase64: serverPub.toString('base64'),
    ivBase64: iv.toString('base64'),
    ciphertextBase64: ciphertext.toString('base64'),
    tagBase64: tag.toString('base64')
  };
}

On the client side, the app uses its private X25519 key to derive the same shared secret, decrypt the AES-GCM payload and render the approval UI. This ensures the RCS provider never sees decrypted data.

Step 4 — Creating the single-use approval URL

Generate a single-use token that embeds the approval id and expiry. Sign the token with your server key (use an asymmetric signature like Ed25519) to prevent tampering.

// Example token structure (JWT-like but signed):
{
  "aid": "approval_12345",
  "doc": "doc_9876",
  "exp": 1680000000,
  "nonce": "random-uuid-v4"
}

// Sign the JSON using Ed25519 and deliver the signed token in the encrypted payload

Because short URLs can be phished or scraped, make sure your single-use URLs are paired with protections. Read up on how to conduct domain due diligence and treat any unexpected short URL with caution.

Step 5 — Send via RCS (provider adapter)

Most RCS vendors accept a JSON payload and a destination phone number. Insert the encrypted blob into the message body as a compact base64 package and include clear human text that doesn’t expose sensitive data.

// Pseudocode for sending
const message = `Approval request from ${requester}. Tap to review.`;
const encryptedPackage = encryptForRecipient(recipientPub, JSON.stringify(payload));

// vendorClient.sendRCS({
//   to: '+14155551234',
//   body: message,
//   data: encryptedPackage // vendor may allow custom data fields
// });

Note: RCS carriers and vendors differ in how they accept rich payloads. If your adapter cannot send binary data, include a short URL that points to your server which serves the encrypted blob over HTTPS and requires the device to present its key-derived proof (see step 6).

Step 6 — Client proof & decryption

When a user taps the approval, the client requests the single-use encrypted blob from your server and proves possession of the private key. Proof can be a signed challenge (Ed25519) using the client private key. The server verifies this signature then returns the encrypted payload or decrypts server-side when permitted.

This prevents an attacker who finds the short URL from retrieving the payload.

Step 7 — Handling device support and capability detection

Not every phone supports RCS or E2EE yet. Build robust detection:

  • Query your RCS provider for per-number capability (many vendors expose a capability API).
  • Keep a local cache of last-known channel status per user with TTL.
  • Allow the user to choose preferred fallback in their profile (email, SMS, in-app).

If RCS is present but E2EE is not available, you still have value: send an encrypted payload as described so providers only see ciphertext. Where an RCS E2EE rollout exists (e.g., certain carriers or iOS/Android combinations in 2026), you may benefit from provider-native encryption — but client-side encryption remains the most reliable.

Step 8 — Email fallback strategy

Email remains the most universally reachable channel. Use it as a reliable fallback with these rules:

  • Send the approval link over TLS (STARTTLS or SMTPS) and sign the message (DKIM, SPF).
  • For sensitive documents, attach a password-protected PDF or use S/MIME/PGP to encrypt the email body.
  • Embed the same single-use token as in the RCS flow and require re-authentication to complete the approval.
  • Indicate clearly the reason for fallback in the message to prevent phishing confusion.

Given the 2026 landscape where major email providers are adding deeper AI integrations, assume server-side email scanning may be enabled by provider policies. When regulatory requirements prohibit this, prefer S/MIME or deliver the encrypted payload as an attachment.

Step 9 — Webhook verification & audit trail

When an approver taps Approve/Reject, the client calls your approval webhook. Always verify:

  • That the provided token is valid (signature + expiry + single-use).
  • The client proof signature to confirm identity.
  • That the action matches the allowed operations for that user.

Store an audit record containing the approval id, the actor id, the timestamp, and a hash of the full payload (SHA-256). Keep raw encrypted blobs only as long as required by compliance. Review best practices on security & privacy checklists to align retention with policy.

Step 10 — Security checklist & compliance

  • Server keys stored in a KMS/HSM with strict rotation policies.
  • Client private keys stored in secure enclave/keystore (Android Keystore / iOS Secure Enclave).
  • Short-lived tokens, single-use URLs and strict expiry windows (e.g., 10–15 minutes for approval clicks).
  • Audit trail retention policy matched to regulation (HIPAA, eIDAS, SOC2).
  • Pen-test and threat modeling for the notification vector and fallback pathways.

Testing & rollout

Run these tests:

  • Capability simulation — emulate RCS available/unavailable and ensure fallback triggers.
  • Interoperability — test across Android OEMs and iOS betas where RCS E2EE is emerging.
  • Key compromise simulation — rotate keys and ensure old tokens are invalidated.
  • Load and retries — simulate high approval bursts and ensure your retry/backoff doesn’t spamming duplicates.

Observability & metrics

Monitor these KPIs:

  • Delivery rate (RCS vs email)
  • Time-to-approval (median and P95)
  • Fallback rate (how often RCS failed and email used)
  • Failed verification attempts (possible fraud indicator)

As of early 2026, watch for these advances and plan to adapt:

  • Native RCS E2EE rollouts — carriers and OS vendors are incrementally enabling MLS-style encryption; when widely available in your target markets, you can relax some client-side complexity but should keep encryption for defense-in-depth.
  • Zero-knowledge approval stores — decouple metadata from content so your service can verify approvals without storing document plaintext.
  • ML-driven fraud detection — combine device signals and message analytics to flag suspicious approval flows before they execute.
  • Interoperable identity standards — decentralized identifiers (DIDs) and verifiable credentials are maturing and can bootstrap trust in cross-org approvals.

Common pitfalls and how to avoid them

  • Sending full documents in RCS — resist the urge; always link to a short-lived secure URL.
  • Assuming provider E2EE equals your E2EE — encrypt client-side for consistency.
  • Long token expiry — short-lived tokens prevent replay and reduce blast radius if leaked.
  • Poor UX during fallback — always inform users why they received email and how to identify genuine messages.

Code sample: simplistic end-to-end flow (high-level)

// 1) Coordinator gets approval request
const approval = createApproval(docId, requesterId);

// 2) Check recipient capabilities
const supportsRCS = await rcsProvider.capabilityCheck(recipientPhone);

if (supportsRCS && recipientHasPubKey(recipientId)) {
  const payload = { aid: approval.id, doc: docId, exp: Date.now() + 10*60*1000 };
  const encrypted = encryptForRecipient(getPubKey(recipientId), JSON.stringify(payload));
  await rcsProvider.send(recipientPhone, 'You have a document to approve', encrypted);
} else {
  // email fallback
  const token = signToken(payload);
  await emailClient.sendSignedEmail(recipientEmail, 'Approval request', buildEmailBody(token));
}

// 3) Approval webhook verifies signature and token, creates audit record

Operational checklist before production

  • Register with an RCS vendor that supports capability queries and custom data fields.
  • Implement client key management with secure storage.
  • Confirm legal/regulatory requirements for your documents and ensure S/MIME or PGP is available if required.
  • Set up KMS for server keys and rotate on schedule.
  • Prepare incident response for key compromise or mass fallback events.

Note: RCS E2EE adoption varies by carrier and market in 2026. Treat client-side encryption as the baseline for privacy and use carrier E2EE as an additional layer when available.

Real-world example: approval speed improvement

In a pilot with 200 SMB users in late 2025, teams using RCS notifications saw median approval time drop from 10.2 hours (email) to 28 minutes (RCS). Fallback to email was used in 12% of cases primarily because recipients were on older devices. Encryption-as-implemented prevented provider-side visibility of sensitive invoice data while preserving auditability.

Final tips

  • Make the user experience frictionless: one tap to open, clear context, and the smallest possible decision UI.
  • Log and surface fallback reasons so you can iteratively reduce those cases.
  • Educate users on how to identify legitimate RCS messages and email fallbacks — reduce phishing risk.

Call to action

If you’re evaluating secure approval workflows in 2026, start with a small, instrumented pilot that implements client-side encryption and automated email fallback. Want a reference implementation? Contact our engineering team at simplyfile.cloud for a starter repo and integration guide tailored to your RCS provider — or sign up for a 30-day trial to test secure RCS approvals with email fallback in your business workflow.

Advertisement

Related Topics

#developer#mobile#security
U

Unknown

Contributor

Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.

Advertisement
2026-02-22T04:38:34.995Z