Skip to main content

SMS CSV export column reference

The Messages → SMS page downloads a CSV from the Export menu in two scopes. Both scopes emit the same column set in the same order, so the file you open is stable across exports. This reference explains every column, with special attention to the destination and lifecycle headers (Currency, Submitted At, Sent At, Delivered At, Country, Network, MCC, MNC) added to the export.

Export scopes: this page vs all results

“Export all results” filters on channel, status, and a created-date window only. Direction and free-text search refinements you applied in the list are not sent to the server — the full-set file can be broader than the on-screen list. Both scopes produce the same columns in the same order. The difference is row count, not schema.

Column-by-column reference

The first six columns are the shared message baseline every channel exports: The SMS page then appends eleven SMS-specific columns: All five timestamp columns (Created At, Submitted At, Sent At, Delivered At, plus scheduled/read/etc. on other channels) are formatted in your dashboard timezone and locale to the second, so the CSV agrees with the on-screen wall clock.

Submitted At vs Created At — one timestamp, two headers

The baseline column set every channel exports includes Created At. The SMS export then adds a synthetic Submitted At column that re-emits created_at under its own header. This is deliberate: operators reconciling SMS against carrier submission logs ask for “submitted at”, not “created at”, and having a dedicated header keeps both vocabularies present without splitting the value. The two cells always carry the same timestamp.

Blank rows and cells — no fallback, no guessing

The export honours a strict blank-cell contract:
  • Country / Network / MCC / MNC blank — the send pipeline never recorded a destination stamp on that row. The exporter surfaces the recorded metadata.dest_country / metadata.mccmnc_operator only; it will not substitute a prefix guess, an HLR re-lookup, or the internal routing supplier. An inbound row follows the same symmetric stamping rule.
  • Delivered At blank — no final DLR has arrived yet.
  • Sent At blank — the row was never dispatched (e.g. still queued, or failed pre-transmission).
  • Price = 0 — the send was never billed (a pre-transmission failure, or a BYO-carrier/absorbed-channel leg billed $0 by design). A positive price always reflects the billed amount.
Treat blank as “not recorded”, not “zero”.

Worked example

Export all results for outbound SMS in a date window; open the file and check one row end to end. A delivered send to a UK recipient:
Reading it right to left:
  1. MCC 234, MNC 15 — the UK + Vodafone pair the send resolved; exported as text so the leading values stay intact in Excel.
  2. Network Vodafone UK — the operator resolved at send time from the HLR/directory, not a supplier name.
  3. Country GB — the destination country stamped when the send was accepted.
  4. Delivered At 6 seconds after Sent At — the carrier DLR round trip.
  5. Sent At vs Submitted At — 2-second queue→dispatch latency between accept-stamp and wire-handoff; Submitted At equals Created At by design.
  6. Currency USD — the code attached to Price 0.0075, verbatim from the message row.
For an undelivered send (no DLR yet), the same row exports with Delivered At blank and often blank Country/Network/MCC/MNC if the pipeline never recorded destination resolution; nothing is inferred.

Troubleshooting

  • Delivered At is blank but you saw “Delivered” in the dashboard. The status chip reflects the latest lifecycle state; the exported delivered_at cell carries only the recorded DLR timestamp. If a status advanced via a path that doesn’t persist a delivered timestamp, the cell stays blank — trust Status for the verdict and Delivered At for the receipt time.
  • Country / Network / MCC are blank on some rows. Expected when the send-time destination resolution never recorded a stamp — the export deliberately does not re-derive country from the phone prefix or re-run HLR at export time. Filter the list by status submitted_no_receipt or check the message detail drawer for what was recorded.
  • Price reads 0 for a row you expect to cost. Only rows that failed before transmission, or legitimate $0-billed legs (BYO-carrier, absorbed-channel), export 0. If a delivered row shows 0, check the message detail drawer’s metadata charge — a mismatch there is a billing-path problem, not an export problem.
  • Excel mangles MCC/MNC. They are exported as text literals precisely so leading zeros survive; if a spreadsheet still reformats them, re-import the CSV marking those two columns as Text rather than General.
  • “Export all results” returned fewer rows than the list suggested. The full-set export caps at 10,000 rows and filters on channel/status/date only — direction and free-text search are not applied server-side. Narrow the date window and re-export.
Shipped in commit 2fc5d08e5f (destination/lifecycle columns on both export scopes).