Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions packages/mock-servers/cloudflare/src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const dashboardEndpoints: Array<DashboardEndpoint> = [
},
{
method: 'POST',
path: `/client/v4/accounts/${fixtureAccount.id}/email-service/send`,
path: `/client/v4/accounts/${fixtureAccount.id}/email/sending/send`,
description: 'Send an outbound email',
requiresAuth: true,
},
Expand Down Expand Up @@ -521,7 +521,14 @@ async function handleEmailSend(
payload_json: JSON.stringify(payload),
})

return envelope({ messageId }, { status: 200 })
return envelope(
{
delivered: Array.isArray(payload.to) ? payload.to : [payload.to],
permanent_bounces: [],
queued: [],
},
{ status: 200 },
)
}

async function routeApi(request: Request, env: MockCloudflareEnv, url: URL) {
Expand Down Expand Up @@ -627,7 +634,7 @@ async function routeApi(request: Request, env: MockCloudflareEnv, url: URL) {
}

const emailMatch = url.pathname.match(
/^\/client\/v4\/accounts\/([^/]+)\/email-service\/send\/?$/,
/^\/client\/v4\/accounts\/([^/]+)\/email\/sending\/send\/?$/,
)
if (emailMatch && request.method === 'POST') {
return handleEmailSend(request, env, emailMatch[1]!)
Expand Down
15 changes: 9 additions & 6 deletions packages/worker/src/app/email/cloudflare-email.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async function startCloudflareMock(token: string) {
await waitForMock(origin)
return mock
} catch (error) {
await mock[Symbol.asyncDispose]()
await stopProcess(proc)
throw error
}
}
Expand Down Expand Up @@ -100,7 +100,7 @@ test('sendCloudflareEmail posts to the mock Cloudflare email API', async () => {
)

expect(sendResult.ok).toBe(true)
expect(sendResult.id).toMatch(/^email_/)
expect(sendResult.id).toBeUndefined()

const response = await fetch(`${mock.origin}/__mocks/messages?token=${token}`)
expect(response.status).toBe(200)
Expand All @@ -122,11 +122,15 @@ test('sendCloudflareEmail posts to the mock Cloudflare email API', async () => {

test('sendCloudflareEmail defaults the API base URL when it is unset', async () => {
const originalFetch = globalThis.fetch
const fetchSpy = vi.fn(async (input: RequestInfo | URL) => {
const fetchSpy = vi.fn(async () => {
return new Response(
JSON.stringify({
success: true,
result: { messageId: 'email_default_base_url' },
result: {
delivered: ['recipient@example.com'],
permanent_bounces: [],
queued: [],
},
}),
{
status: 200,
Expand All @@ -153,12 +157,11 @@ test('sendCloudflareEmail defaults the API base URL when it is unset', async ()

expect(result).toEqual({
ok: true,
id: 'email_default_base_url',
})
expect(fetchSpy).toHaveBeenCalledTimes(1)
const [input] = fetchSpy.mock.calls[0]!
expect(String(input)).toBe(
`https://api.cloudflare.com/client/v4/accounts/${mockAccountId}/email-service/send`,
`https://api.cloudflare.com/client/v4/accounts/${mockAccountId}/email/sending/send`,
)
} finally {
globalThis.fetch = originalFetch
Expand Down
5 changes: 4 additions & 1 deletion packages/worker/src/app/email/cloudflare-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type CloudflareApiEnvelope = {
}>
result?: {
messageId?: string
delivered?: string[]
permanent_bounces?: string[]
queued?: string[]
}
}

Expand Down Expand Up @@ -71,7 +74,7 @@ async function sendViaCloudflareApi(
message: OutboundEmail,
): Promise<CloudflareSendResult> {
const endpoint = new URL(
`client/v4/accounts/${config.accountId}/email-service/send`,
`client/v4/accounts/${config.accountId}/email/sending/send`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vestigial messageId extraction yields perpetually undefined id

Low Severity

After switching to the /email/sending/send endpoint, the API response no longer includes a messageId field — it returns delivered, permanent_bounces, and queued instead. Yet sendViaCloudflareApi still attempts to extract payload.result.messageId and expose it as id on CloudflareSendResult. This means id is now always undefined, making both the extraction logic (lines 125–128) and the messageId field on CloudflareApiEnvelope dead code. A future developer seeing id?: string on the return type might rely on it, not realizing it's never populated.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b80269d. Configure here.

normalizeApiBaseUrl(config.apiBaseUrl),
)
let response: Response
Expand Down
Loading