knadh/listmonk · error
campaigns.fieldInvalidFromEmail
Error message
campaigns.fieldInvalidFromEmail
What it means
validateCampaignFields in cmd/campaigns.go rejects a campaign request whose FromEmail is neither empty nor empty-defaulted from config, when it fails both the reFromAddress regex and importer.SanitizeEmail(). It means the supplied sender address is not a parseable/valid e-mail the outgoing mail system can use.
Source
Thrown at cmd/campaigns.go:685
}
// Create a sample campaign message.
msg, err := a.manager.NewCampaignMessage(camp, sub)
if err != nil {
a.log.Printf("error rendering message: %v", err)
return echo.NewHTTPError(http.StatusNotFound, a.i18n.Ts("templates.errorRendering", "error", err.Error()))
}
return a.manager.PushCampaignMessage(msg)
}
// validateCampaignFields validates incoming campaign field values.
func (a *App) validateCampaignFields(c campReq) (campReq, error) {
if c.FromEmail == "" {
c.FromEmail = a.cfg.FromEmail
} else if !reFromAddress.Match([]byte(c.FromEmail)) {
if _, err := a.importer.SanitizeEmail(c.FromEmail); err != nil {
return c, errors.New(a.i18n.T("campaigns.fieldInvalidFromEmail"))
}
}
if !strHasLen(c.Name, 1, stdInputMaxLen) {
return c, errors.New(a.i18n.T("campaigns.fieldInvalidName"))
}
// Larger char limit for subject as it can contain {{ go templating }} logic.
if !strHasLen(c.Subject, 1, 5000) {
return c, errors.New(a.i18n.T("campaigns.fieldInvalidSubject"))
}
// If no content-type is specified, default to richtext.
if c.ContentType != models.CampaignContentTypeRichtext &&
c.ContentType != models.CampaignContentTypeHTML &&
c.ContentType != models.CampaignContentTypePlain &&
c.ContentType != models.CampaignContentTypeVisual &&
c.ContentType != models.CampaignContentTypeMarkdown {View on GitHub (pinned to 670c01717d)
Solutions
- Send a plain valid e-mail address (e.g. 'sender@domain.com') in the from_email field.
- Omit from_email entirely to inherit the default a.cfg.FromEmail configured in the app config.
- Strip whitespace/display-name wrappers before sending; use net/mail.ParseAddress client-side to pre-validate.
- If a display name is needed, configure the sender name field separately rather than embedding '<>' in the address.
Example fix
// before
{"from_email": "Marketing <marketing@example.com>"}
// after
{"from_email": "marketing@example.com", "from_name": "Marketing"} Defensive patterns
Strategy: validation
Validate before calling
// validate from_email before calling the campaign API
function isValidFromEmail(v) {
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(String(v || '').trim());
}
// or, omit the field to inherit the server default:
const payload = { name, subject, lists };
if (fromEmail) payload.from_email = fromEmail; Type guard
function isPlainEmail(v: unknown): v is string {
return typeof v === 'string' && /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v.trim());
} Try / catch
try {
await api.createCampaign(payload);
} catch (e) {
if (e.message.includes('fieldInvalidFromEmail')) {
throw new Error(`from_email "${payload.from_email}" is not a valid address`);
}
throw e;
} Prevention
- Never embed display names like 'Name <addr>' in from_email; use the separate name field.
- Trim whitespace and strip zero-width characters before sending.
- Prefer omitting from_email to use the app-wide default sender.
When it happens
Trigger: POST/PUT campaign endpoints (CreateCampaign, UpdateCampaign) or TestCampaign with a from_email value like 'not-an-email', 'John <john>' (malformed), or containing stray whitespace/characters that fail both the regex and sanitization.
Common situations: Typing a display name into the from_email field instead of an address, pasting 'Name <addr@x.com>' when the API expects just the address, or copying an address with hidden unicode/whitespace from a document.
Related errors
- globals.messages.invalidFields
- campaigns.fieldInvalidName
- campaigns.fieldInvalidSubject
- campaigns.fieldInvalidSendAt
- campaigns.fieldInvalidListIDs
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/d6590b844ca9cb0c.
Report an issue: GitHub.