feat: do not enforce TLD on email (#2075)

fix #1846
This commit is contained in:
Ludovic Ortega
2025-10-20 17:24:24 +03:00
committed by GitHub
parent 48a61d812b
commit b34ca1543a
8 changed files with 47 additions and 11 deletions

View File

@@ -221,7 +221,9 @@ class EmailAgent
this.getSettings(),
payload.notifyUser.settings?.pgpKey
);
if (validator.isEmail(payload.notifyUser.email)) {
if (
validator.isEmail(payload.notifyUser.email, { require_tld: false })
) {
await email.send(
this.buildMessage(
type,
@@ -283,7 +285,7 @@ class EmailAgent
this.getSettings(),
user.settings?.pgpKey
);
if (validator.isEmail(user.email)) {
if (validator.isEmail(user.email, { require_tld: false })) {
await email.send(
this.buildMessage(type, payload, user.email, user.displayName)
);

View File

@@ -37,7 +37,7 @@ authRoutes.get('/me', isAuthenticated(), async (req, res) => {
const settings = await getSettings();
if (
settings.notifications.agents.email.options.userEmailRequired &&
!validator.isEmail(user.email)
!validator.isEmail(user.email, { require_tld: false })
) {
user.warnings.push('userEmailRequired');
logger.warn(`User ${user.username} has no valid email address`);

View File

@@ -5,6 +5,7 @@ import { Transition } from '@headlessui/react';
import axios from 'axios';
import { Field, Formik } from 'formik';
import { useIntl } from 'react-intl';
import validator from 'validator';
import * as Yup from 'yup';
const messages = defineMessages('components.Login', {
@@ -36,7 +37,11 @@ const AddEmailModal: React.FC<AddEmailModalProps> = ({
const EmailSettingsSchema = Yup.object().shape({
email: Yup.string()
.email(intl.formatMessage(messages.validationEmailFormat))
.test(
'email',
intl.formatMessage(messages.validationEmailFormat),
(value) => !value || validator.isEmail(value, { require_tld: false })
)
.required(intl.formatMessage(messages.validationEmailRequired)),
});

View File

@@ -10,6 +10,7 @@ import Image from 'next/image';
import Link from 'next/link';
import { useState } from 'react';
import { useIntl } from 'react-intl';
import validator from 'validator';
import * as Yup from 'yup';
const messages = defineMessages('components.ResetPassword', {
@@ -29,7 +30,11 @@ const ResetPassword = () => {
const ResetSchema = Yup.object().shape({
email: Yup.string()
.email(intl.formatMessage(messages.validationemailrequired))
.test(
'email',
intl.formatMessage(messages.validationemailrequired),
(value) => !value || validator.isEmail(value, { require_tld: false })
)
.required(intl.formatMessage(messages.validationemailrequired)),
});

View File

@@ -11,6 +11,7 @@ import { useState } from 'react';
import { useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR, { mutate } from 'swr';
import validator from 'validator';
import * as Yup from 'yup';
const messages = defineMessages('components.Settings.Notifications', {
@@ -77,7 +78,11 @@ const NotificationsEmail = () => {
.required(intl.formatMessage(messages.validationEmail)),
otherwise: Yup.string().nullable(),
})
.email(intl.formatMessage(messages.validationEmail)),
.test(
'email',
intl.formatMessage(messages.validationEmail),
(value) => !value || validator.isEmail(value, { require_tld: false })
),
smtpHost: Yup.string().when('enabled', {
is: true,
then: Yup.string()

View File

@@ -8,6 +8,7 @@ import axios from 'axios';
import { Field, Form, Formik } from 'formik';
import { FormattedMessage, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import validator from 'validator';
import * as Yup from 'yup';
const messages = defineMessages('components.Login', {
@@ -90,7 +91,11 @@ function JellyfinSetup({
(value) => !value || !value.endsWith('/')
),
email: Yup.string()
.email(intl.formatMessage(messages.validationemailformat))
.test(
'email',
intl.formatMessage(messages.validationemailformat),
(value) => !value || validator.isEmail(value, { require_tld: false })
)
.required(intl.formatMessage(messages.validationemailrequired)),
username: Yup.string().required(
intl.formatMessage(messages.validationusernamerequired)

View File

@@ -36,6 +36,7 @@ import { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import validator from 'validator';
import * as Yup from 'yup';
import JellyfinImportModal from './JellyfinImportModal';
@@ -210,7 +211,11 @@ const UserList = () => {
),
email: Yup.string()
.required()
.email(intl.formatMessage(messages.validationEmail)),
.test(
'email',
intl.formatMessage(messages.validationEmail),
(value) => !value || validator.isEmail(value, { require_tld: false })
),
password: Yup.lazy((value) =>
!value
? Yup.string()

View File

@@ -23,6 +23,7 @@ import { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import validator from 'validator';
import * as Yup from 'yup';
const messages = defineMessages(
@@ -105,10 +106,18 @@ const UserGeneralSettings = () => {
user?.id === 1 ||
(user?.userType !== UserType.JELLYFIN && user?.userType !== UserType.EMBY)
? Yup.string()
.email(intl.formatMessage(messages.validationemailformat))
.test(
'email',
intl.formatMessage(messages.validationemailformat),
(value) =>
!value || validator.isEmail(value, { require_tld: false })
)
.required(intl.formatMessage(messages.validationemailrequired))
: Yup.string().email(
intl.formatMessage(messages.validationemailformat)
: Yup.string().test(
'email',
intl.formatMessage(messages.validationemailformat),
(value) =>
!value || validator.isEmail(value, { require_tld: false })
),
discordId: Yup.string()
.nullable()