diff --git a/changelog.mdx b/changelog.mdx
index 0b443f9..17bdcf6 100644
--- a/changelog.mdx
+++ b/changelog.mdx
@@ -4,6 +4,19 @@ description: "New features, improvements, and fixes across the Sendmux platform.
rss: true
---
+
+ ## Bug fixes
+
+Outgoing usage now counts every accepted To, CC, and BCC recipient occurrence. If the same address appears more than once, each accepted occurrence is billed; addresses rejected before acceptance are not charged.
+
+Delivery log summaries show accepted and rejected recipient totals. Log details list each recipient outcome in sending order.
+
+Blind-copy addresses remain part of delivery without being exposed in the delivered message headers.
+
+Repeated account setup requests reuse work already in progress. When a newer setup email is issued, its link replaces the earlier link so only the latest setup link can be used.
+
+
+
## Bug fixes
diff --git a/guides/billing.mdx b/guides/billing.mdx
index a39b8be..5415bdc 100644
--- a/guides/billing.mdx
+++ b/guides/billing.mdx
@@ -20,10 +20,14 @@ Sendmux charges email usage from the team balance.
| Activity | Rate |
| --- | --- |
-| Standard outgoing mail through your own providers | `$0.15 / 1,000 emails` |
-| Outgoing mail through the managed Amazon SES route | `$0.25 / 1,000 emails` |
+| Standard outgoing mail through your own providers | `$0.15 / 1,000 provider-accepted recipient occurrences` |
+| Outgoing mail through the managed Amazon SES route | `$0.25 / 1,000 provider-accepted recipient occurrences` |
| Accepted inbound mail | `$0.15 / 1,000 emails` |
+For outgoing mail, each provider-accepted To, CC, or BCC recipient occurrence is billed. Addresses rejected before provider acceptance are not charged.
+
+If the same address appears in more than one recipient field, each provider-accepted occurrence is billed separately.
+
Inbound usage is counted when a message is accepted into a mailbox. Mail rejected by mailbox allow or block rules is not billed.
Usage transactions can be grouped, so the transaction table may show one **Incoming email usage** line for several received messages in a short period.
diff --git a/openapi-app.json b/openapi-app.json
index 439773f..39d3d2c 100644
--- a/openapi-app.json
+++ b/openapi-app.json
@@ -311,9 +311,168 @@
],
"type": "object"
},
+ "DeliveryLogDetail": {
+ "additionalProperties": false,
+ "properties": {
+ "accepted_recipient_count": {
+ "description": "Recipient occurrences accepted by the provider, or null when no recipient snapshot exists",
+ "maximum": 50,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "attempts": {
+ "type": "number"
+ },
+ "created_at": {
+ "description": "ISO 8601 creation timestamp",
+ "type": "string"
+ },
+ "from_email": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "id": {
+ "description": "Log public ID",
+ "example": "dlog_clxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "type": "string"
+ },
+ "message_id": {
+ "description": "Email Message-ID header",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "provider_id": {
+ "description": "Provider public ID",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "provider_name": {
+ "description": "Provider display name",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "recipient_count": {
+ "description": "Total recipient occurrences, or null when no recipient snapshot exists",
+ "maximum": 50,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "recipients": {
+ "description": "Ordered recipient outcome snapshot for this send, or null when no snapshot exists",
+ "items": {
+ "$ref": "#/components/schemas/DeliveryLogRecipient"
+ },
+ "maxItems": 50,
+ "type": [
+ "array",
+ "null"
+ ]
+ },
+ "rejected_recipient_count": {
+ "description": "Recipient occurrences rejected by the provider, or null when no recipient snapshot exists",
+ "maximum": 50,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "sent_at": {
+ "description": "ISO 8601 timestamp when email was sent",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "sent_from_email": {
+ "description": "The actual from address used for delivery after transformation. NULL if no transformation occurred or for older log entries.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "size_bytes": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "status": {
+ "enum": [
+ "pending",
+ "sent",
+ "failed",
+ "rejected"
+ ],
+ "type": "string"
+ },
+ "status_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "subject": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "to_email": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "provider_id",
+ "provider_name",
+ "message_id",
+ "from_email",
+ "sent_from_email",
+ "to_email",
+ "subject",
+ "status",
+ "status_reason",
+ "attempts",
+ "sent_at",
+ "size_bytes",
+ "created_at",
+ "recipient_count",
+ "accepted_recipient_count",
+ "rejected_recipient_count",
+ "recipients"
+ ],
+ "type": "object"
+ },
"DeliveryLogItem": {
"additionalProperties": false,
"properties": {
+ "accepted_recipient_count": {
+ "description": "Recipient occurrences accepted by the provider, or null when no recipient snapshot exists",
+ "maximum": 50,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
"attempts": {
"type": "number"
},
@@ -353,6 +512,24 @@
"null"
]
},
+ "recipient_count": {
+ "description": "Total recipient occurrences, or null when no recipient snapshot exists",
+ "maximum": 50,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "rejected_recipient_count": {
+ "description": "Recipient occurrences rejected by the provider, or null when no recipient snapshot exists",
+ "maximum": 50,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
"sent_at": {
"description": "ISO 8601 timestamp when email was sent",
"type": [
@@ -415,7 +592,10 @@
"attempts",
"sent_at",
"size_bytes",
- "created_at"
+ "created_at",
+ "recipient_count",
+ "accepted_recipient_count",
+ "rejected_recipient_count"
],
"type": "object"
},
@@ -456,7 +636,7 @@
{
"properties": {
"data": {
- "$ref": "#/components/schemas/DeliveryLogItem"
+ "$ref": "#/components/schemas/DeliveryLogDetail"
},
"meta": {
"$ref": "#/components/schemas/ResponseMeta"
@@ -470,6 +650,50 @@
],
"unevaluatedProperties": false
},
+ "DeliveryLogRecipient": {
+ "additionalProperties": false,
+ "properties": {
+ "email": {
+ "description": "Recipient email address",
+ "format": "email",
+ "type": "string"
+ },
+ "reason": {
+ "description": "Recipient-specific rejection reason when available",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "status": {
+ "description": "Provider acceptance outcome",
+ "enum": [
+ "accepted",
+ "rejected"
+ ],
+ "type": "string"
+ },
+ "type": {
+ "description": "Recipient header type when known",
+ "enum": [
+ "to",
+ "cc",
+ "bcc"
+ ],
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "required": [
+ "email",
+ "type",
+ "status",
+ "reason"
+ ],
+ "type": "object"
+ },
"DomainDeletedResponse": {
"allOf": [
{
diff --git a/openapi-sending.json b/openapi-sending.json
index fa2138b..156ebcd 100644
--- a/openapi-sending.json
+++ b/openapi-sending.json
@@ -337,19 +337,19 @@
"type": "array"
},
"bcc": {
- "description": "BCC recipients (max 100)",
+ "description": "BCC recipients (subject to 50 total To, CC, and BCC recipients)",
"items": {
"$ref": "#/components/schemas/Recipient"
},
- "maxItems": 100,
+ "maxItems": 49,
"type": "array"
},
"cc": {
- "description": "CC recipients (max 100)",
+ "description": "CC recipients (subject to 50 total To, CC, and BCC recipients)",
"items": {
"$ref": "#/components/schemas/Recipient"
},
- "maxItems": 100,
+ "maxItems": 49,
"type": "array"
},
"custom_headers": {