---
title: Private submission capture
description: Capture bounded private request/outcome payloads with explicit permission and retention controls.
---

Use `capturedEmailSenderLayer` from `@corven/email-sdk/capture` only when your application is authorized to retain message payloads:

```ts
import { Effect, Layer } from "effect";
import { Email, emailLayer } from "@corven/email-sdk";
import type { EmailMessageInput } from "@corven/email-sdk";
import { capturedEmailSenderLayer, EmailSubmissionCapture } from "@corven/email-sdk/capture";
import { recordingSenderLayer } from "@corven/email-sdk/testing";

export const captureSyntheticSubmission = Effect.fnUntraced(function* captureSyntheticSubmission(
  message: EmailMessageInput,
) {
  const email = yield* Email;
  const capture = yield* EmailSubmissionCapture;
  const receipt = yield* email.send(message);
  const snapshot = yield* capture.snapshot;
  const purgedRecordCount = yield* capture.purgeRecords;

  return { purgedRecordCount, receipt, snapshot };
});

export const capturedSyntheticEmailLayer = emailLayer().pipe(
  Layer.provideMerge(
    capturedEmailSenderLayer(recordingSenderLayer, {
      capacity: 10,
      maxBytes: 1_048_576,
      privateData: "AuthorizePayloadCapture",
    }),
  ),
);
```

The example uses a recorder, so it does not contact a provider. In production, substitute the configured sender without changing the capture/query ownership.

## Configure retention

Supply `capacity`, `maxBytes` and `privateData: "AuthorizePayloadCapture"`. Retention is bounded by record count and UTF-8 bytes. Oversized or evicted data is reflected in `truncated`; the view is not a complete audit log.

`EmailSubmissionCapture.snapshot` returns `records`, `retainedBytes`, `closed` and `truncated`. Each record's `payloadJson` is Redacted. Unwrap and decode it only in an explicitly authorized private path using the exported payload Schema; do not log it as a diagnostic shortcut.

## Purge the visible view

`purgeRecords` removes visible records and returns the count removed. It does not securely erase copies already returned to callers, clear every private application store or reset duplicate-prevention evidence.

Keep sending and querying in the same Layer acquisition. Define access control and retention outside the SDK before replacing the synthetic sender with a real account. Use [minimal observations](/composition/observations) when payloads are unnecessary.
