fix: add utf8 email validation support (#6239)

Co-authored-by: Thomas <thomas@ajnart.fr>
This commit is contained in:
Nam NguyenandThomas authored and GitHub committed 2026-07-10 17:28:22 +02:00
1 parent 7c152cf4fe
commit 7d93df04dd
6 files changed
+43 -13

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
import { z } from "zod/v4";
export const utf8EmailSchema = z.email({ pattern: z.regexes.unicodeEmail });
export const optionalEmailSchema = utf8EmailSchema.or(z.string().length(0)).optional();
export const nullableEmailSchema = utf8EmailSchema
.or(z.literal(""))
.transform((value) => (value === "" ? null : value))
.optional()
.nullable();
export const requiredNullableEmailSchema = utf8EmailSchema
.or(z.literal(""))
.transform((value) => (value === "" ? null : value))
.nullable();
+16
View File
@@ -4,6 +4,7 @@ import { z } from "zod/v4";
import type { TranslationFunction } from "@homarr/translation";
import { createCustomErrorParams, zodErrorMap } from "./i18n";
import { utf8EmailSchema } from "../email";
const expectError = (error: z.core.$ZodIssue, key: string) => {
expect(error.message).toContain(key);
@@ -111,4 +112,19 @@ describe("i18n", () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expectError(result.error.issues[0]!, "boardAlreadyExists");
});
test("should validate UTF8SMTP email with umlauts", () => {
const result = utf8EmailSchema.safeParse("jörg@example.com");
expect(result.success).toBe(true);
});
test("should validate UTF8SMTP email with unicode domain", () => {
const result = utf8EmailSchema.safeParse("user@münchen.de");
expect(result.success).toBe(true);
});
test("should validate standard ASCII emails", () => {
const result = utf8EmailSchema.safeParse("user@example.com");
expect(result.success).toBe(true);
});
});
+3 -8
View File
@@ -6,6 +6,7 @@ import type { TranslationObject } from "@homarr/translation";
import { zodEnumFromArray } from "./enums";
import { createCustomErrorParams } from "./form/i18n";
import { nullableEmailSchema, optionalEmailSchema } from "./email";
// We always want the lowercase version of the username to compare it in a case-insensitive way
export const usernameSchema = z.string().trim().toLowerCase().min(3).max(255);
@@ -42,7 +43,7 @@ export const userBaseCreateSchema = z.object({
username: usernameSchema,
password: userPasswordSchema,
confirmPassword: z.string(),
email: z.string().email().or(z.string().length(0)).optional(),
email: optionalEmailSchema,
});
export const userCreateSchema = addConfirmPasswordRefinement(userBaseCreateSchema).and(
@@ -85,13 +86,7 @@ export const userRegistrationApiSchema = userRegistrationSchema.and(
export const userEditProfileSchema = z.object({
id: z.string(),
name: usernameSchema,
email: z
.string()
.email()
.or(z.literal(""))
.transform((value) => (value === "" ? null : value))
.optional()
.nullable(),
email: nullableEmailSchema,
});
const baseChangePasswordSchema = z.object({