Table of Contents


Managing Email Templates with the REST API

Email templates and their per-language versions are ordinary platform entities, so they are managed through the standard REST API v3 entity endpoints. A template holds the source-language Subject and Body; each translation is a child record.

There is no send-email endpoint in the REST API. The API writes template data; sends are triggered by automations, or by the Send Test action in the Setup UI. For how a template is localized when it is actually sent, see Email Template Localization at Send Time.


Entities

EntityKey prefixRole
EmailTemplate7ODThe template. Its Subject and Body are the source language.
EmailTemplateLanguage7PWOne translation. Master-detail child of EmailTemplate; reparenting is not allowed.

There is no child record for the source language - the parent is the source.

EmailTemplate fields

FieldTypeConstraints
NamestringRequired, 120 characters. Not enforced unique.
SubjectstringRequired, 255 characters. Supports merge tokens.
BodystringMultiline formula expression. No length cap.
TypepicklistText | HTML. Defaults to Text. Not updateable after create.
IsActiveboolThe "Ready For Use" flag.
Descriptionstring512 characters.
ReplyTostring512 characters, validated as an email address.
FullBrandingboolHTML branding mode. The HTML-only restriction is applied by the template editor, not the entity layer — a direct REST write is not gated on it.
Tagsstring255 characters. Semicolon-separated; normalized on write to 50 characters per tag.
IsStandardboolSystem-template flag. Host-writable only; non-host callers cannot delete a record where this is true.
EmailTemplateLanguagescollectionAccepted as an embedded array on create. Not a stored column.

EmailTemplateLanguage fields

FieldTypeConstraints
EmailTemplateIdstringRequired. Master-detail parent.
LanguagestringRequired. Must be an active language on the portal, matched case-insensitively.
SubjectstringRequired, 255 characters.
Bodystring64,000 characters, multiline.

Endpoints

All standard entity operations apply. Entity names in the path are case-insensitive.

MethodRoutePurpose
GET/api/3.0/entity/emailtemplate/{id}Read one template
GET/api/3.0/entity/emailtemplateList templates
POST/api/3.0/queryMEQL query
POST/api/3.0/entity/emailtemplateCreate - single object or an array for bulk
PATCH/api/3.0/entity/emailtemplate/{id}Partial update
PUT/api/3.0/entity/emailtemplate?uniqueField={field}Upsert by a unique field
DELETE/api/3.0/entity/emailtemplate/{id}Delete - cascades to child translations

The same operations are available on /api/3.0/entity/emailtemplatelanguage/... for translation records.


Creating a Template with Translations

Translations can be supplied inline on create, as an embedded array:

POST /api/3.0/entity/emailtemplate
Content-Type: application/json

{
	"Name": "Welcome Email",
	"Type": "HTML",
	"Subject": "Welcome, {!Contact.FirstName}",
	"Body": "<p>Hello {!Contact.FirstName}</p>",
	"IsActive": true,
	"EmailTemplateLanguages": [
		{ "Language": "fr", "Subject": "Bienvenue", "Body": "<p>Bonjour</p>" },
		{ "Language": "de", "Subject": "Willkommen", "Body": "<p>Hallo</p>" }
	]
}

This is not atomic. The child translations are written after the parent has already been committed, outside a shared transaction. If a child fails validation, the parent still exists. Verify the children after a create, and be prepared to retry just the failed rows.

Querying templates

POST /api/3.0/query

SELECT Id, Name, Type, IsActive FROM EmailTemplate WHERE IsActive = true

MEQL string literals use double quotes. See MEQL Reference.


Validation

RuleMessage
Translation language must be active on the portalUnsupported language code.
One translation per template per languageA localized version already exists for this language.
Type cannot change after createThe template type cannot be changed after creation.
Type must be a recognized valueType must be 'Text' or 'HTML'.

Two write-time transformations happen silently and are worth knowing about:

  • HTML bodies are sanitized. Script, iframe, frameset and input elements and a fixed set of on* event-handler attributes are stripped; iframes are restricted to a host whitelist. This applies to the template and to every translation. Content you post back may therefore differ from what you sent.
  • Tags are normalized. Split on semicolons, trimmed, first character capitalized, de-duplicated case-insensitively, and truncated to 50 characters per tag.

Permissions

  • Standard per-entity Read / Create / Edit / Delete permission on EmailTemplate is enforced inside every action. Host users bypass the checks.
  • Customer and Partner role types are denied outright on EmailTemplate - View, Create, Edit and Delete are all None. A token belonging to a portal user cannot read or write templates at all.
  • Non-host callers cannot delete a template where IsStandard is true.
  • Deleting a template cascades to all of its translations with no per-child confirmation. There is no soft delete.

Behavior to Design Around

  • Type is immutable. To change a template from Text to HTML, create a new record.
  • Name is not unique, but package deployment matches templates by name. Avoid duplicate names in any org you deploy to or from.
  • No versioning. There is no version field or history table for templates or translations, and no staleness flag when a parent changes after its translations were written. If you need to detect drift, store your own hash of the source at translation time.
  • Translations are not exposed to the chatbot tool surface. The UpsertEmailTemplate MCP tool and the generic entity tools operate on the parent EmailTemplate only, and AI-authored drafts are always written in the source language.

See More


Email Template Localization at Send Time >>

Last updated on 8/7/2026

Attachments