Skip to main content

Email Logs Guide

The Email Logs API provides access to detailed delivery status and activity information for all emails sent through EDITH.


Overview​

Email logs allow you to:

  • Track email delivery status
  • View open and click activity
  • Debug delivery issues
  • Generate reports and analytics
  • Monitor campaign performance

Get Email Logs​

Endpoint​

GET /v1/email/logs

Authentication​

Requires Bearer token authentication.

Query Parameters​

All parameters are optional and can be combined for precise filtering. Every query is automatically scoped to your account — you never pass a tenant or account ID. Note the date defaults and limits below the table.

This list is exhaustive. Any query parameter not named here is rejected with 400 "Invalid query parameter: <name>" — the endpoint does not ignore unknown parameters.

ParameterTypeDescription
emailstringFilter by recipient email address (exact match)
recipientDomainstringFilter by recipient's email domain (exact match)
refIdstringFilter by email reference ID (returned when sending)
statusstringFilter by delivery status
fromAddressstringFilter by sender email address (exact match)
subjectstringFilter by email subject (exact match)
campaignIdstringFilter by campaign ID
recipientTypestringFilter by recipient type: "to", "cc", "bcc"
failedReasonstringFilter by failure reason
openedbooleantrue returns only emails that have been opened at least once, false only those never opened
clickedbooleantrue returns only emails with at least one tracked click, false only those never clicked
prioritystringFilter by the priority the email was sent with
startCreatedAtstringStart date for creation date filter (RFC3339 format)
endCreatedAtstringEnd date for creation date filter (RFC3339 format)
startDeliveredDatestringStart date for delivery date filter (RFC3339 format)
endDeliveredDatestringEnd date for delivery date filter (RFC3339 format)
pageSizeintegerNumber of results per page (default: 20, max: 50)
pageTokenstringOpaque cursor for the next page (see Pagination)

Defaults & Limits​

These rules are enforced by the API — read them before building queries:

  • Default window is the last 7 days. If you send neither startCreatedAt nor endCreatedAt, the API returns the most recent 7 days.
  • A date window cannot exceed 7 days. A wider range returns 400 "date range cannot exceed 7 days". To cover a longer period, page through it in ≤ 7-day windows.
  • Send startCreatedAt and endCreatedAt together. Providing only one returns 400 ("endCreatedAt is required" / "startCreatedAt is required"), and startCreatedAt must not be after endCreatedAt.
  • pageSize must be 1–50 (default 20). Values outside that range are rejected with 400 "pageSize must be between 1 and 50" — they are not silently clamped.
  • The same 7-day defaults and limits apply to the delivery-date window (startDeliveredDate / endDeliveredDate).

Email Status Values​

status is matched exactly — it is used verbatim as an index key, so it is case-sensitive and not normalized. Pass one of the values below; anything else (for example delivered or bounced in lowercase) simply returns no results rather than an error.

StatusDescription
QUEUEDAccepted and queued for sending
FAILEDThe send attempt failed
MAIL_DELIVEREDRecipient's mail server accepted the email
MAIL_OPENEDRecipient opened the email (requires open tracking)
MAIL_CLICKEDRecipient clicked a link (requires click tracking)
MAIL_BOUNCEEmail bounced (soft or hard)
MAIL_UNSUBSCRIBEDRecipient unsubscribed

Status reflects the latest event for that recipient, so an email that was delivered and then opened reads MAIL_OPENED. To find every email a recipient opened regardless of later activity, filter on opened=true instead.

These are the same values as the event field on webhooks — with the two pre-send states, QUEUED and FAILED, which only ever appear here.


Example Requests​

Get All Logs (Paginated)​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?pageSize=20" \
-H "Authorization: Bearer YOUR_TOKEN"

Filter by Recipient Email​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?email=customer@example.com" \
-H "Authorization: Bearer YOUR_TOKEN"

Filter by Status​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?status=MAIL_BOUNCE" \
-H "Authorization: Bearer YOUR_TOKEN"

Filter by Campaign​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?campaignId=welcome-series-2024" \
-H "Authorization: Bearer YOUR_TOKEN"

Filter by Date Range​

Send startCreatedAt and endCreatedAt together, within a 7-day window:

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?startCreatedAt=2024-01-15T00:00:00Z&endCreatedAt=2024-01-21T23:59:59Z" \
-H "Authorization: Bearer YOUR_TOKEN"

Filter by Reference ID​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?refId=01JC3BBW8S9YGX2VNKG5MD7BTA" \
-H "Authorization: Bearer YOUR_TOKEN"

Combine Multiple Filters​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?campaignId=promo-jan&status=MAIL_DELIVERED" \
-H "Authorization: Bearer YOUR_TOKEN"

Response Format​

{
"success": true,
"emailLogs": [
{
"refId": "01JC3BBW8S9YGX2VNKG5MD7BTA",
"accountId": 12345,
"tenantId": 67890,
"fromAddress": "notifications@mail.yourcompany.com",
"recipientAddress": "customer@example.com",
"recipientDomain": "example.com",
"recipientType": "to",
"subject": "Your Order Confirmation",
"status": "MAIL_OPENED",
"priority": "0",
"campaignId": "order-confirmation",
"opened": true,
"clicked": true,
"failedReason": "",
"createdAt": "2024-01-15T10:30:00Z",
"deliveredDate": "2024-01-15T10:30:05Z",
"updatedAt": "2024-01-15T11:45:00Z",
"track": {
"MAIL_OPENED": [
{
"time": "2024-01-15T11:00:00Z",
"ip": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"browser_name": "Chrome",
"browser_version": "120.0",
"os": "Windows",
"device_type": "desktop",
"platform": "desktop",
"country": "US",
"city": "New York",
"region": "NY",
"timezone": "America/New_York",
"bot": false
}
],
"MAIL_CLICKED": [
{
"time": "2024-01-15T11:05:00Z",
"ip": "192.168.1.1",
"url": "https://yourcompany.com/orders/12345",
"user_agent": "Mozilla/5.0...",
"browser_name": "Chrome",
"os": "Windows",
"device_type": "desktop",
"country": "US",
"city": "New York",
"bot": false
}
]
}
}
],
"nextPageToken": "eyJJZCI6IjAxSkM0...",
"totalCount": 1
}

Response Fields Explained​

Response Envelope​

FieldTypeDescription
successbooleantrue when the request succeeded
emailLogsarrayThe matching log entries for this page
nextPageTokenstringCursor for the next page. Omitted when there are no more results — see Pagination
totalCountintegerNumber of records returned in this response — not a global total across all pages

Email Log Entry​

FieldTypeDescription
refIdstringUnique reference ID for this email (returned when sending)
accountIdintegerYour account identifier
tenantIdintegerTenant/organization identifier
fromAddressstringSender email address
recipientAddressstringRecipient email address
recipientDomainstringDomain portion of recipient email
recipientTypestringHow recipient was addressed: "to", "cc", "bcc"
subjectstringEmail subject line
statusstringLatest delivery status — see Email Status Values
prioritystringThe priority the email was sent with: 0 (normal) or 1 (high)
campaignIdstringCampaign identifier (if provided when sending)
openedbooleanWhether email has been opened (if tracking enabled)
clickedbooleanWhether any links were clicked (if tracking enabled)
failedReasonstringReason for failure; empty string when the email did not fail
createdAtstringWhen the email was created (RFC3339)
deliveredDatestringWhen the email was delivered (RFC3339)
updatedAtstringLast update timestamp (RFC3339)
trackobjectDetailed tracking events (opens, clicks)

Track Object​

track is keyed by event name, not by a friendly label, and each key holds every occurrence of that event in the order it happened. Keys are absent until the first such event, so a never-opened email has "track": {}.

KeyTypeDescription
MAIL_OPENEDarrayOne entry per open
MAIL_CLICKEDarrayOne entry per tracked click

Each entry has the same shape as the tracking object on webhooks:

FieldTypeDescription
timestringWhen the event occurred (RFC3339)
ipstringClient IP
user_agentstringRaw User-Agent header
browser_name / browser_versionstringParsed from the User-Agent
os / device_type / platformstringParsed from the User-Agent
country / city / region / timezonestringResolved from the IP
urlstringThe clicked URL — MAIL_CLICKED entries only
botbooleantrue when the event was attributed to a bot or scanner rather than a person

Pagination​

The API uses cursor-based pagination. Each response returns a nextPageToken while more results exist; pass it back as pageToken to fetch the next page.

When to use it: a single page returns at most 50 records, so any query that matches more than pageSize rows — exporting a busy 7-day window, pulling every bounce for a campaign — needs paging to read the full set.

Initial Request​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?status=MAIL_BOUNCE&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"

Next Page​

Use the nextPageToken from the previous response as pageToken, keeping every other filter identical:

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?status=MAIL_BOUNCE&pageSize=50&pageToken=eyJJZCI6IjAxSkM0..." \
-H "Authorization: Bearer YOUR_TOKEN"

Pagination Tips​

  • pageSize must be 1–50 (default 20); out-of-range values are rejected, not clamped.
  • nextPageToken is omitted from the response when there are no more results — stop paging when it's absent.
  • Treat the token as opaque: pass it back exactly as received. Don't parse, build, or modify it.
  • Keep your filters identical across pages — changing a filter mid-pagination invalidates the cursor.
  • totalCount is the size of the current page, not a count of all matching records. To get a full total, page to the end and sum the pages.
  • Remember the 7-day window cap: to page across a longer period, repeat the loop for each ≤ 7-day window.

Use Cases​

1. Track Specific Email Delivery​

# Using the ref_id from send response
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?refId=01JC3BBW8S9YGX2VNKG5MD7BTA" \
-H "Authorization: Bearer YOUR_TOKEN"

2. Find Bounced Emails​

curl -X GET "https://api.sparrowmailer.com/v1/email/logs?status=MAIL_BOUNCE&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"

3. Emails from a Sender​

Find everything sent from a given fromAddress, then narrow with common combinations:

# All emails from a sender
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?fromAddress=notifications@mail.yourcompany.com" \
-H "Authorization: Bearer YOUR_TOKEN"

# Sender + only failures
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?fromAddress=notifications@mail.yourcompany.com&status=FAILED" \
-H "Authorization: Bearer YOUR_TOKEN"

Any of these can also be scoped to a date window — see Filter by Date Range.

4. Emails to a Recipient​

Pull a recipient's full history, or focus on a specific outcome:

# Every email to a recipient
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?email=customer@example.com" \
-H "Authorization: Bearer YOUR_TOKEN"

# Only what landed as a primary (To) recipient and was delivered
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?email=customer@example.com&recipientType=to&status=MAIL_DELIVERED" \
-H "Authorization: Bearer YOUR_TOKEN"

5. Campaign Performance​

# All sends for a campaign
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?campaignId=black-friday-2024" \
-H "Authorization: Bearer YOUR_TOKEN"

# Delivered vs. bounced for a campaign
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?campaignId=black-friday-2024&status=MAIL_BOUNCE" \
-H "Authorization: Bearer YOUR_TOKEN"

6. Domain-Wide Issues​

# Check if emails to a specific domain are failing
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?recipientDomain=problematic-domain.com&status=FAILED" \
-H "Authorization: Bearer YOUR_TOKEN"

7. Recent Failures​

# Recent failures (defaults to the last 7 days)
curl -X GET "https://api.sparrowmailer.com/v1/email/logs?status=FAILED&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"

Best Practices​

1. Use Specific Filters​

Narrow down results to improve performance:

# Good: specific filters
?campaignId=promo-jan&status=MAIL_DELIVERED

# If you add a date bound, add both — a lone startCreatedAt returns 400
?campaignId=promo-jan&startCreatedAt=2024-01-15T00:00:00Z # 400: endCreatedAt is required

2. Store Reference IDs​

When sending emails, store the ref_id for easy lookup:

const response = await sendEmail(payload);
await database.saveEmailRecord({
orderId: order.id,
emailRefId: response.ref_id,
sentAt: new Date()
});

3. Use Campaign IDs Consistently​

Tag emails with meaningful campaign IDs:

const payload = {
// ... email content
campaign_id: `${emailType}-${year}-${quarter}`
// e.g., "welcome-2024-q1", "invoice-2024-q1"
};

4. Handle Pagination Properly​

async function getAllBouncedEmails() {
const allLogs = [];
let pageToken = null;

do {
const params = new URLSearchParams({
status: 'bounced',
pageSize: '50'
});
if (pageToken) params.set('pageToken', pageToken);

const response = await fetch(
`https://api.sparrowmailer.com/v1/email/logs?${params}`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const data = await response.json();

allLogs.push(...data.emailLogs);
pageToken = data.nextPageToken;
} while (pageToken);

return allLogs;
}

5. Monitor Failed Emails​

Set up regular checks for failures:

// Daily bounce report — pass both bounds (within 7 days)
const now = new Date();
const yesterday = new Date(now.getTime() - 86400000);
const bouncedEmails = await getEmailLogs({
status: 'bounced',
startCreatedAt: yesterday.toISOString(),
endCreatedAt: now.toISOString()
});

if (bouncedEmails.length > threshold) {
alertOps('High bounce rate detected');
}

Common Errors​

ErrorCauseSolution
Invalid query parameter: <name>An unrecognized query parameter was sentUse only the parameters listed above
date range cannot exceed 7 daysstartCreatedAt–endCreatedAt spans more than 7 daysSplit into ≤ 7-day windows and page through them
endCreatedAt is required / startCreatedAt is requiredOnly one date bound was sentSend both bounds together, or neither (defaults to last 7 days)
startCreatedAt cannot be after endCreatedAtDate bounds are reversedEnsure start ≤ end
pageSize must be between 1 and 50pageSize outside the allowed rangeUse a value from 1 to 50
Wrong date formatDate not RFC3339Use RFC3339 (e.g., 2024-01-15T10:30:00Z)
invalid page tokenpageToken was altered or malformedPass the nextPageToken exactly as returned; don't modify it
UnauthorizedInvalid or expired bearer tokenRefresh authentication token