knadh/listmonk · error

invalid e-mail address

Error message

invalid e-mail address

What it means

ErrInvalidEmail is the package-level sentinel returned by utils.SanitizeEmail when the input is not a well-formed bare email address (Go net/mail parsing; display-name components are rejected). ValidateEmail builds on it: an address is valid iff SanitizeEmail returns no error. Callers can compare with errors.Is to distinguish format errors from domain-policy rejections.

Source

Thrown at internal/utils/utils.go:13

package utils

import (
	"crypto/rand"
	"errors"
	"net/mail"
	"net/url"
	"path"
	"strings"
)

// ErrInvalidEmail is returned by SanitizeEmail for malformed input.
var ErrInvalidEmail = errors.New("invalid e-mail address")

// ValidateEmail reports whether s is a correctly formed bare e-mail address
// (no display name component).
func ValidateEmail(s string) bool {
	_, err := SanitizeEmail(s)
	return err == nil
}

// SanitizeEmail trims, lowercases, and validates s as a bare e-mail address
// (no display name) and returns the canonical form. Returns ErrInvalidEmail
// for anything `mail.ParseAddress` rejects or for input with a display name.
func SanitizeEmail(s string) (string, error) {
	s = strings.ToLower(strings.TrimSpace(s))
	em, err := mail.ParseAddress(s)
	if err != nil || em.Address != s {
		return "", ErrInvalidEmail
	}
	return em.Address, nil

View on GitHub (pinned to 670c01717d)

Solutions

  1. Trim whitespace and strip display-name components, keeping only the addr-spec before validation.
  2. Fix the offending value to a proper user@domain.tld form.
  3. Use ValidateEmail as a cheap pre-check before persisting or importing.
  4. In your own code, compare with errors.Is(err, utils.ErrInvalidEmail) to branch on invalid format specifically.

Example fix

// before
email := "John Doe <john@acme.com>"
// after
email := "john@acme.com"
Defensive patterns

Strategy: validation

Validate before calling

if !utils.ValidateEmail(input) {
    return fmt.Errorf("%q is not a valid bare email address", input)
}

Type guard

func isBareEmail(s string) bool {
    if strings.Contains(s, "<") || strings.Contains(s, ">") {
        return false // display-name form is rejected by SanitizeEmail
    }
    return utils.ValidateEmail(s)
}

Try / catch

addr, err := utils.SanitizeEmail(input)
if errors.Is(err, utils.ErrInvalidEmail) {
    return fmt.Errorf("invalid email format: %w", err)
}

Prevention

When it happens

Trigger: Calling utils.SanitizeEmail (directly or via importer.SanitizeEmail / ValidateEmail) with a string failing address parsing: empty input, no '@', illegal characters, spaces, or a 'Name <addr>' display-name form.

Common situations: Importing CSVs with dirty data; accepting form input without client-side validation; storing 'John <john@x.com>' strings copied from mail clients; untrimmed newlines/tabs inside the address.

Related errors


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/7a094f4d392ea80f. Report an issue: GitHub.