From a993ec0780268051c6ae595d81199febf377ece1 Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 16:44:42 -0700 Subject: [PATCH 1/7] chore: update package versions --- apps/backend/package.json | 2 +- apps/dashboard/package.json | 2 +- apps/dev-launchpad/package.json | 2 +- apps/e2e/package.json | 2 +- apps/hosted-components/package.json | 2 +- apps/mock-oauth-server/package.json | 2 +- docs/package.json | 2 +- examples/cjs-test/package.json | 2 +- examples/convex/package.json | 2 +- examples/demo/package.json | 2 +- examples/docs-examples/package.json | 2 +- examples/e-commerce/package.json | 2 +- examples/js-example/package.json | 2 +- examples/lovable-react-18-example/package.json | 2 +- examples/middleware/package.json | 2 +- examples/react-example/package.json | 2 +- examples/supabase/package.json | 2 +- packages/dashboard-ui-components/package.json | 2 +- packages/init-stack/package.json | 2 +- packages/js/package.json | 2 +- packages/react/package.json | 2 +- packages/stack-cli/package.json | 2 +- packages/stack-sc/package.json | 2 +- packages/stack-shared/package.json | 2 +- packages/stack-ui/package.json | 2 +- packages/stack/package.json | 2 +- packages/template/package-template.json | 2 +- packages/template/package.json | 2 +- sdks/implementations/swift/package.json | 2 +- sdks/spec/package.json | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/apps/backend/package.json b/apps/backend/package.json index 26b5f8a79..96b304746 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/backend", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "type": "module", diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 81d7b2aa9..dbe4be1f4 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/dashboard", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/apps/dev-launchpad/package.json b/apps/dev-launchpad/package.json index 88edcafa1..aaa971024 100644 --- a/apps/dev-launchpad/package.json +++ b/apps/dev-launchpad/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/dev-launchpad", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/apps/e2e/package.json b/apps/e2e/package.json index dcced2537..1f908b208 100644 --- a/apps/e2e/package.json +++ b/apps/e2e/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/e2e-tests", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "type": "module", diff --git a/apps/hosted-components/package.json b/apps/hosted-components/package.json index bb5cf8b1a..5f4872972 100644 --- a/apps/hosted-components/package.json +++ b/apps/hosted-components/package.json @@ -1,7 +1,7 @@ { "name": "@stackframe/hosted-components", "private": true, - "version": "2.8.77", + "version": "2.8.78", "type": "module", "scripts": { "dev": "vite dev --port ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}09", diff --git a/apps/mock-oauth-server/package.json b/apps/mock-oauth-server/package.json index 1cacd657b..00198a1e4 100644 --- a/apps/mock-oauth-server/package.json +++ b/apps/mock-oauth-server/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/mock-oauth-server", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "main": "index.js", diff --git a/docs/package.json b/docs/package.json index c263b04b1..e221f7d83 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/stack-docs", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "description": "", "main": "index.js", diff --git a/examples/cjs-test/package.json b/examples/cjs-test/package.json index ba934adab..543a2063f 100644 --- a/examples/cjs-test/package.json +++ b/examples/cjs-test/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/example-cjs-test", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/examples/convex/package.json b/examples/convex/package.json index fc4bcebcc..24a204c42 100644 --- a/examples/convex/package.json +++ b/examples/convex/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/convex-example", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/examples/demo/package.json b/examples/demo/package.json index 13907b5d3..706eebce9 100644 --- a/examples/demo/package.json +++ b/examples/demo/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/example-demo-app", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "description": "", "private": true, diff --git a/examples/docs-examples/package.json b/examples/docs-examples/package.json index de1ca703c..e9f316926 100644 --- a/examples/docs-examples/package.json +++ b/examples/docs-examples/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/docs-examples", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "description": "", "private": true, diff --git a/examples/e-commerce/package.json b/examples/e-commerce/package.json index a786bd1be..8f24813c6 100644 --- a/examples/e-commerce/package.json +++ b/examples/e-commerce/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/e-commerce-demo", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/examples/js-example/package.json b/examples/js-example/package.json index cc92147c0..d7ae3edd7 100644 --- a/examples/js-example/package.json +++ b/examples/js-example/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/js-example", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "description": "", diff --git a/examples/lovable-react-18-example/package.json b/examples/lovable-react-18-example/package.json index 3b210af78..1332482e2 100644 --- a/examples/lovable-react-18-example/package.json +++ b/examples/lovable-react-18-example/package.json @@ -1,7 +1,7 @@ { "name": "@stackframe/lovable-react-18-example", "private": true, - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "type": "module", "scripts": { diff --git a/examples/middleware/package.json b/examples/middleware/package.json index ead225904..6dab0f1ed 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/example-middleware-demo", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/examples/react-example/package.json b/examples/react-example/package.json index 3dc8f82ca..4d2878f3e 100644 --- a/examples/react-example/package.json +++ b/examples/react-example/package.json @@ -1,7 +1,7 @@ { "name": "react-example", "private": true, - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "type": "module", "scripts": { diff --git a/examples/supabase/package.json b/examples/supabase/package.json index b982f7bea..259fed802 100644 --- a/examples/supabase/package.json +++ b/examples/supabase/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/example-supabase", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "private": true, "scripts": { diff --git a/packages/dashboard-ui-components/package.json b/packages/dashboard-ui-components/package.json index dd9956ab8..74936a9a2 100644 --- a/packages/dashboard-ui-components/package.json +++ b/packages/dashboard-ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/dashboard-ui-components", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/init-stack/package.json b/packages/init-stack/package.json index 0a903775b..1bbb50071 100644 --- a/packages/init-stack/package.json +++ b/packages/init-stack/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/init-stack", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "description": "The setup wizard for Stack. https://stack-auth.com", "main": "dist/index.mjs", diff --git a/packages/js/package.json b/packages/js/package.json index 4e62e79b1..4c8e710d4 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -1,7 +1,7 @@ { "//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)", "name": "@stackframe/js", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/react/package.json b/packages/react/package.json index d0febd419..85b082785 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,7 +1,7 @@ { "//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)", "name": "@stackframe/react", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/stack-cli/package.json b/packages/stack-cli/package.json index 36ef0a5e5..a2f3041de 100644 --- a/packages/stack-cli/package.json +++ b/packages/stack-cli/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/stack-cli", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "description": "The CLI for Stack Auth. https://stack-auth.com", "main": "dist/index.js", diff --git a/packages/stack-sc/package.json b/packages/stack-sc/package.json index a68d4c893..3baf4addc 100644 --- a/packages/stack-sc/package.json +++ b/packages/stack-sc/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/stack-sc", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "exports": { "./force-react-server": { diff --git a/packages/stack-shared/package.json b/packages/stack-shared/package.json index ebd2ad306..416e741cd 100644 --- a/packages/stack-shared/package.json +++ b/packages/stack-shared/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/stack-shared", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "scripts": { "build": "rimraf dist && tsdown", diff --git a/packages/stack-ui/package.json b/packages/stack-ui/package.json index 194731959..e88d4d60b 100644 --- a/packages/stack-ui/package.json +++ b/packages/stack-ui/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/stack-ui", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/stack/package.json b/packages/stack/package.json index 9a86bdb90..4c2864087 100644 --- a/packages/stack/package.json +++ b/packages/stack/package.json @@ -1,7 +1,7 @@ { "//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)", "name": "@stackframe/stack", - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/template/package-template.json b/packages/template/package-template.json index 04f2fcf95..dd79e3d04 100644 --- a/packages/template/package-template.json +++ b/packages/template/package-template.json @@ -11,7 +11,7 @@ "//": "NEXT_LINE_PLATFORM template", "private": true, - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/template/package.json b/packages/template/package.json index 1db4db5c0..15e6bab89 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -2,7 +2,7 @@ "//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)", "name": "@stackframe/template", "private": true, - "version": "2.8.77", + "version": "2.8.78", "repository": "https://github.com/stack-auth/stack-auth", "sideEffects": false, "main": "./dist/index.js", diff --git a/sdks/implementations/swift/package.json b/sdks/implementations/swift/package.json index 86d541276..885d00f5b 100644 --- a/sdks/implementations/swift/package.json +++ b/sdks/implementations/swift/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/swift-sdk", - "version": "2.8.77", + "version": "2.8.78", "private": true, "description": "Stack Auth Swift SDK", "scripts": { diff --git a/sdks/spec/package.json b/sdks/spec/package.json index 43f2d54c9..df74c7a62 100644 --- a/sdks/spec/package.json +++ b/sdks/spec/package.json @@ -1,6 +1,6 @@ { "name": "@stackframe/sdk-spec", - "version": "2.8.77", + "version": "2.8.78", "private": true, "description": "Stack Auth SDK specification files", "scripts": {} From c062ae62d272ad2f7ac6a813302a3a2bdc0fc60f Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 16:57:13 -0700 Subject: [PATCH 2/7] Make migration backwards-compatible --- .../migration.sql | 4 ++++ .../migration.sql | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/backend/prisma/migrations/20260308000000_add_signup_fraud_protection/migration.sql b/apps/backend/prisma/migrations/20260308000000_add_signup_fraud_protection/migration.sql index 492c35db6..acb95e1f2 100644 --- a/apps/backend/prisma/migrations/20260308000000_add_signup_fraud_protection/migration.sql +++ b/apps/backend/prisma/migrations/20260308000000_add_signup_fraud_protection/migration.sql @@ -10,6 +10,10 @@ ALTER TABLE "ProjectUser" ADD COLUMN "signUpEmailNormalized" TEXT, ADD COLUMN "signUpEmailBase" TEXT; +-- Backward compatibility during rollout: old backends omit `signedUpAt` on +-- INSERT, so set a default immediately in the first migration. +ALTER TABLE "ProjectUser" ALTER COLUMN "signedUpAt" SET DEFAULT CURRENT_TIMESTAMP; + -- Add the risk score bounds without validating existing rows yet. ALTER TABLE "ProjectUser" ADD CONSTRAINT "ProjectUser_risk_score_bot_range" diff --git a/apps/backend/prisma/migrations/20260308000002_finalize_signup_fraud_protection/migration.sql b/apps/backend/prisma/migrations/20260308000002_finalize_signup_fraud_protection/migration.sql index bb227baeb..08a4f00a0 100644 --- a/apps/backend/prisma/migrations/20260308000002_finalize_signup_fraud_protection/migration.sql +++ b/apps/backend/prisma/migrations/20260308000002_finalize_signup_fraud_protection/migration.sql @@ -28,13 +28,6 @@ ALTER TABLE "ProjectUser" VALIDATE CONSTRAINT "ProjectUser_risk_score_bot_range" -- RUN_OUTSIDE_TRANSACTION_SENTINEL ALTER TABLE "ProjectUser" VALIDATE CONSTRAINT "ProjectUser_risk_score_free_trial_abuse_range"; --- Enforce `signedUpAt` after the backfill is complete. Set a DEFAULT first so --- that inserts omitting the column still get a sensible value (CURRENT_TIMESTAMP). --- SPLIT_STATEMENT_SENTINEL --- SINGLE_STATEMENT_SENTINEL --- RUN_OUTSIDE_TRANSACTION_SENTINEL -ALTER TABLE "ProjectUser" ALTER COLUMN "signedUpAt" SET DEFAULT CURRENT_TIMESTAMP; - -- SPLIT_STATEMENT_SENTINEL -- SINGLE_STATEMENT_SENTINEL -- RUN_OUTSIDE_TRANSACTION_SENTINEL From 0a21d301dd8072de90def4c01309375592886af3 Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 23:23:09 -0700 Subject: [PATCH 3/7] Fix Emailable retries --- apps/backend/src/lib/emailable.tsx | 86 +++++++++++++++--------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/apps/backend/src/lib/emailable.tsx b/apps/backend/src/lib/emailable.tsx index 14fce3beb..bb6f70c47 100644 --- a/apps/backend/src/lib/emailable.tsx +++ b/apps/backend/src/lib/emailable.tsx @@ -1,5 +1,6 @@ import { getEnvVariable, getNodeEnvironment } from "@stackframe/stack-shared/dist/utils/env"; import { captureError, StackAssertionError } from "@stackframe/stack-shared/dist/utils/errors"; +import { wait } from "@stackframe/stack-shared/dist/utils/promises"; import { traceSpan } from "@stackframe/stack-shared/dist/utils/telemetry"; import createEmailableClient from "emailable"; @@ -41,17 +42,15 @@ function validateVerifyResponse(value: unknown) { async function verifyWithRetries(verifyFn: () => Promise, maxAttempts: number, delayBaseMs: number) { for (let i = 0; i < maxAttempts; i++) { - try { - return await verifyFn(); - } catch (error) { - const code = (error != null && typeof error === "object" && !Array.isArray(error)) - ? Reflect.get(error, "code") - : null; - if (code !== 249) throw error; // only retry rate-limit errors - if (i < maxAttempts - 1) { - await new Promise(r => setTimeout(r, (Math.random() + 0.5) * delayBaseMs * (2 ** i))); + const res: any = await verifyFn(); + if (!("state" in res)) { + if ("message" in res && res.message.includes("Your request is taking longer than normal")) { + await wait((Math.random() + 0.5) * delayBaseMs * (2 ** i)); + continue; } + throw new StackAssertionError("Emailable returned an unexpected response body", { response: res }); } + return res; } throw new StackAssertionError("Timed out while verifying email address with Emailable"); } @@ -81,46 +80,45 @@ export async function checkEmailWithEmailable( _clientFactory?: (apiKey: string) => { verify: (email: string) => Promise }, }, ): Promise { - const rawApiKey = getEnvVariable("STACK_EMAILABLE_API_KEY", ""); - const emailDomain = email.split("@")[1]?.toLowerCase() ?? ""; + try { + const rawApiKey = getEnvVariable("STACK_EMAILABLE_API_KEY", ""); + const emailDomain = email.split("@")[1]?.toLowerCase() ?? ""; - // Always reject the explicit test domain, regardless of API key - if (emailDomain === EMAILABLE_NOT_DELIVERABLE_TEST_DOMAIN) { - const testResponse = buildTestUndeliverableResponse(email); - return { status: "not-deliverable", emailableResponse: testResponse, emailableScore: testResponse.score }; - } + // Always reject the explicit test domain, regardless of API key + if (emailDomain === EMAILABLE_NOT_DELIVERABLE_TEST_DOMAIN) { + const testResponse = buildTestUndeliverableResponse(email); + return { status: "not-deliverable", emailableResponse: testResponse, emailableScore: testResponse.score }; + } - if (!rawApiKey) { - if (["development", "test"].includes(getNodeEnvironment())) { + if (!rawApiKey) { + if (["development", "test"].includes(getNodeEnvironment())) { + return { status: "ok", emailableScore: null }; + } + throw new StackAssertionError("STACK_EMAILABLE_API_KEY must not be empty; set it to 'disable_email_validation' to disable email validation"); + } + + const apiKey = rawApiKey === "disable_email_validation" ? "" : rawApiKey; + if (!apiKey || isReservedTestDomain(emailDomain)) { return { status: "ok", emailableScore: null }; } - throw new StackAssertionError("STACK_EMAILABLE_API_KEY must not be empty; set it to 'disable_email_validation' to disable email validation"); + + const clientFactory = options?._clientFactory ?? createEmailableClient; + const retryDelayBase = options?.retryExponentialDelayBaseMs ?? RETRY_BACKOFF_BASE_MS; + + return await traceSpan("checking email address with Emailable", async () => { + const client = clientFactory(apiKey); + const raw = await verifyWithRetries(() => client.verify(email), 4, retryDelayBase); + const response = validateVerifyResponse(raw); + + if (response.state === "undeliverable" || response.disposable) { + return { status: "not-deliverable", emailableResponse: response, emailableScore: response.score }; + } + return { status: "ok", emailableScore: response.score }; + }); + } catch (error) { + captureError("emailable-api-error", error); + return { status: "error", error, emailableScore: null }; } - - const apiKey = rawApiKey === "disable_email_validation" ? "" : rawApiKey; - if (!apiKey || isReservedTestDomain(emailDomain)) { - return { status: "ok", emailableScore: null }; - } - - const clientFactory = options?._clientFactory ?? createEmailableClient; - const retryDelayBase = options?.retryExponentialDelayBaseMs ?? RETRY_BACKOFF_BASE_MS; - - return await traceSpan("checking email address with Emailable", async () => { - const client = clientFactory(apiKey); - let raw: unknown; - try { - raw = await verifyWithRetries(() => client.verify(email), 4, retryDelayBase); - } catch (error) { - captureError("emailable-api-error", error); - return { status: "error", error, emailableScore: null }; - } - const response = validateVerifyResponse(raw); - - if (response.state === "undeliverable" || response.disposable) { - return { status: "not-deliverable", emailableResponse: response, emailableScore: response.score }; - } - return { status: "ok", emailableScore: response.score }; - }); } From 24cc2cfe163f480036be1c741eecc873219c6222 Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 23:24:05 -0700 Subject: [PATCH 4/7] Improved information on failed Emailable emails --- apps/backend/src/lib/emailable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/lib/emailable.tsx b/apps/backend/src/lib/emailable.tsx index bb6f70c47..6a1a8bda5 100644 --- a/apps/backend/src/lib/emailable.tsx +++ b/apps/backend/src/lib/emailable.tsx @@ -116,7 +116,7 @@ export async function checkEmailWithEmailable( return { status: "ok", emailableScore: response.score }; }); } catch (error) { - captureError("emailable-api-error", error); + captureError("emailable-api-error", new StackAssertionError("Error while checking email address with Emailable", { cause: error, email, options })); return { status: "error", error, emailableScore: null }; } } From 502823df0a3352af0b9a740ecd605ec0ade01fad Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 23:33:07 -0700 Subject: [PATCH 5/7] Add undeliverable email address --- apps/backend/src/lib/emailable.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/backend/src/lib/emailable.tsx b/apps/backend/src/lib/emailable.tsx index 6a1a8bda5..5177ad38c 100644 --- a/apps/backend/src/lib/emailable.tsx +++ b/apps/backend/src/lib/emailable.tsx @@ -111,6 +111,7 @@ export async function checkEmailWithEmailable( const response = validateVerifyResponse(raw); if (response.state === "undeliverable" || response.disposable) { + console.log("Checked email address with Emailable and found it to be not deliverable", { email, response }); return { status: "not-deliverable", emailableResponse: response, emailableScore: response.score }; } return { status: "ok", emailableScore: response.score }; From af783e1df9ce09015f90ea08dcc24e83c01b14bb Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 23:45:16 -0700 Subject: [PATCH 6/7] Still send emails to disposable email addresses --- apps/backend/src/lib/emailable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/lib/emailable.tsx b/apps/backend/src/lib/emailable.tsx index 5177ad38c..31be65fc5 100644 --- a/apps/backend/src/lib/emailable.tsx +++ b/apps/backend/src/lib/emailable.tsx @@ -110,7 +110,7 @@ export async function checkEmailWithEmailable( const raw = await verifyWithRetries(() => client.verify(email), 4, retryDelayBase); const response = validateVerifyResponse(raw); - if (response.state === "undeliverable" || response.disposable) { + if (response.state === "undeliverable") { console.log("Checked email address with Emailable and found it to be not deliverable", { email, response }); return { status: "not-deliverable", emailableResponse: response, emailableScore: response.score }; } From 371f9afbcc15fd14529cc0b9786062c2c9e91f8b Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Wed, 25 Mar 2026 23:59:36 -0700 Subject: [PATCH 7/7] Better emailable logging --- apps/backend/src/lib/emailable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/lib/emailable.tsx b/apps/backend/src/lib/emailable.tsx index 31be65fc5..b62011689 100644 --- a/apps/backend/src/lib/emailable.tsx +++ b/apps/backend/src/lib/emailable.tsx @@ -108,10 +108,10 @@ export async function checkEmailWithEmailable( return await traceSpan("checking email address with Emailable", async () => { const client = clientFactory(apiKey); const raw = await verifyWithRetries(() => client.verify(email), 4, retryDelayBase); + console.log("Received emailable response", { email, raw }); const response = validateVerifyResponse(raw); if (response.state === "undeliverable") { - console.log("Checked email address with Emailable and found it to be not deliverable", { email, response }); return { status: "not-deliverable", emailableResponse: response, emailableScore: response.score }; } return { status: "ok", emailableScore: response.score };