diff --git a/firestore-send-email/CHANGELOG.md b/firestore-send-email/CHANGELOG.md index 1491388c8..6d30cd4a0 100644 --- a/firestore-send-email/CHANGELOG.md +++ b/firestore-send-email/CHANGELOG.md @@ -1,3 +1,7 @@ +## Version 0.2.3 + +fix: remove strict validation of email "from" field + ## Version 0.2.2 fix: fix validation of payloads diff --git a/firestore-send-email/extension.yaml b/firestore-send-email/extension.yaml index 4b1f55161..d0b34a42a 100644 --- a/firestore-send-email/extension.yaml +++ b/firestore-send-email/extension.yaml @@ -13,7 +13,7 @@ # limitations under the License. name: firestore-send-email -version: 0.2.2 +version: 0.2.3 specVersion: v1beta displayName: Trigger Email from Firestore diff --git a/firestore-send-email/functions/__tests__/e2e/sendgrid.test.ts b/firestore-send-email/functions/__tests__/e2e/sendgrid.test.ts index 815b13d42..c53e296cf 100644 --- a/firestore-send-email/functions/__tests__/e2e/sendgrid.test.ts +++ b/firestore-send-email/functions/__tests__/e2e/sendgrid.test.ts @@ -68,8 +68,7 @@ const TEST_COLLECTIONS = ["emailCollection", "emailTemplates"] as const; beforeAll(() => { // Initialize with emulator settings admin.initializeApp({ - projectId: "dev-extensions-testing", - databaseURL: "http://localhost:8080?ns=dev-extensions-testing", + projectId: "demo-test", }); // Point Firestore to the emulator @@ -141,5 +140,45 @@ const TEST_COLLECTIONS = ["emailCollection", "emailTemplates"] as const; expect(updatedData?.delivery.info?.rejected).toEqual([]); expect(updatedData?.delivery.info?.pending).toEqual([]); }); + + test("should process an email with friendly name in from field", async () => { + const db = admin.firestore(); + + const testData = { + message: { + attachments: [], + html: "

Test email with friendly name

", + text: "Test email with friendly name", + subject: "Test Friendly Name", + from: "Friendly Firebaser test@example.com", + }, + to: TEST_EMAIL, + }; + + // Write the document to the emulator + const docRef = db.collection("emailCollection").doc("test-friendly-name"); + await docRef.set(testData); + + // Wait a bit for the function to process + await new Promise((resolve) => setTimeout(resolve, 2000)); + + // Verify the document was updated + const doc = await docRef.get(); + const updatedData = doc.data(); + + // Assert the delivery state was updated to SUCCESS + console.log("updatedData with friendly name", updatedData); + expect(updatedData?.delivery.state).toBe("SUCCESS"); + expect(updatedData?.delivery.attempts).toBe(1); + expect(updatedData?.delivery.endTime).toBeDefined(); + expect(updatedData?.delivery.error).toBeNull(); + + // Verify SendGrid specific info + expect(updatedData?.delivery.info).toBeDefined(); + expect(updatedData?.delivery.info?.messageId).toBeDefined(); + expect(updatedData?.delivery.info?.accepted).toContain(TEST_EMAIL); + expect(updatedData?.delivery.info?.rejected).toEqual([]); + expect(updatedData?.delivery.info?.pending).toEqual([]); + }); } ); diff --git a/firestore-send-email/functions/__tests__/validation.test.ts b/firestore-send-email/functions/__tests__/validation.test.ts index cedff391f..1d74fca27 100644 --- a/firestore-send-email/functions/__tests__/validation.test.ts +++ b/firestore-send-email/functions/__tests__/validation.test.ts @@ -91,6 +91,18 @@ describe("validatePayload", () => { expect(() => validatePayload(validPayload)).not.toThrow(); }); + it("should validate payload with friendly name in from field", () => { + const validPayload = { + to: "test@example.com", + from: "Friendly Firebaser test@example.com", + message: { + subject: "Test Subject", + text: "Test message", + }, + }; + expect(() => validatePayload(validPayload)).not.toThrow(); + }); + it("should validate a template payload without html/text fields", () => { const validPayload = { to: "test@example.com", diff --git a/firestore-send-email/functions/package.json b/firestore-send-email/functions/package.json index 4180a2fa2..f2eae28d6 100644 --- a/firestore-send-email/functions/package.json +++ b/firestore-send-email/functions/package.json @@ -14,7 +14,7 @@ "test:local": "concurrently --kill-others \"npm run local:emulator\" \"npm run testIfEmulatorRunning\"", "test:watch": "concurrently \"npm run local:emulator\" \"jest --watch\"", "test:coverage": "concurrently --kill-others \"npm run local:emulator\" \"wait-on tcp:4001 && jest --coverage\"", - "test:e2e:sendgrid": "E2E_SENDGRID=true jest __tests__/e2e/sendgrid.test.ts", + "test:e2e:sendgrid": "cd ../../_emulator && firebase emulators:exec --project=demo-test \" cd ../firestore-send-email/functions && E2E_SENDGRID=true jest __tests__/e2e/sendgrid.test.ts\"", "generate-readme": "firebase ext:info .. --markdown > ../README.md" }, "keywords": [], diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index 6b8b8af03..0d13af707 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -116,10 +116,7 @@ const templateSchema = z.object({ /** * Schema for email recipients (single email or array of emails). */ -const recipientSchema = z.union([ - z.string().email(), - z.array(z.string().email()), -]); +const recipientSchema = z.union([z.string(), z.array(z.string())]); /** * Schema for arrays of UIDs. @@ -137,8 +134,8 @@ const payloadSchema = z toUids: uidArraySchema.optional(), ccUids: uidArraySchema.optional(), bccUids: uidArraySchema.optional(), - from: z.string().email().optional(), - replyTo: z.string().email().optional(), + from: z.string().optional(), + replyTo: z.string().optional(), message: baseMessageSchema.optional(), template: templateSchema.optional(), sendGrid: sendGridSchema.optional(),