# Message Log

The tenant dashboard Message Log lists messages newest-first with a stable ID tie-breaker. It supports exact identifier, Sender ID, and recipient searches plus tenant-owned application, direction, Sender ID, recipient, and UTC range filters. The `To UTC` boundary is exclusive and a complete range may not exceed 31 days.

Recipients remain masked in the list and details. Message content is decrypted by the model/service layer and escaped by the view; list previews are limited to 80 characters. Details use the same public-status projection as the status API and assemble their timeline only from persisted message events, attempts, and delivery receipts.

Public-status filtering is intentionally unavailable in this foundation. The public status derives from both `message_status` and `delivery_status`; a production-safe indexed filter needs a separately approved query/index or denormalized projection.

Open **Messaging**, apply filters, and use the **Details** anchor for the authoritative lifecycle view. No provider secrets, credentials, raw encrypted values, or internal numeric IDs are rendered.

## CSV export

CSV export uses the current Message Log filters and requires explicit From UTC and To UTC values. To is exclusive, the maximum range is 31 days, and exports containing more than 100,000 matching rows are rejected rather than truncated. Empty results produce a valid header-only CSV.

Recipients remain masked and message content is limited to a normalized 160-character preview. Every string cell is protected against spreadsheet formula injection, and embedded line breaks are normalized. CSV is streamed in deterministic newest-first cursor pages with bounded memory. XLSX is not supported by this milestone.
