Communications
Save an email template
/a/EmailTemplate_save
Save the complete email-template editor state, sanitize its HTML, and persist inline images.
When to use this endpoint
Use EmailTemplate_save for CRM1 or CRM2 email-template editor submissions. It is the dedicated full-save contract and should be preferred over generic mapped updates.
Authentication and permissions
The request must authenticate with signed API-key fields or a logged-in CRM session. The handler requires login and performs no additional page or role-permission check.
The read or write is limited to the authenticated tenant. Notice endpoints that say “current user” use the authenticated session user ID within that tenant.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer-compatible | Yes | Existing template ID. It must convert to an integer of at least 1. |
name | String | Yes | Trimmed nonblank template name, unique across other active and archived templates under the database collation. |
body | HTML string | Yes | Complete body. Script, iframe, and meta elements are removed. A blank result becomes {{BODY}}; inline base64 images are uploaded and their src values are replaced. |
subject | String | Yes | Trimmed subject, at most 100 bytes as measured by strlen. Blank is accepted. |
from_email | Email string | Yes | Trimmed sender. Blank input falls back to nonblank tenant setting default-from-email; the final value must pass PHP email validation. Placeholder sender codes are not accepted by this route. |
is_default | Integer-compatible | Yes | Stored integer default flag. A false-like value clears this row’s flag; a newly truthy row clears existing defaults first. |
type | Integer-compatible | No | Legacy template category; defaults to 0. The endpoint accepts any integer and does not validate the category list. |
form_id | Integer-compatible | When type is 7 | Stored as meta.form_id only for type 7. It is integer-converted and the referenced form is not checked. |
Example request
$result = FM_api('EmailTemplate_save', [
'id' => '152004',
'name' => 'Service completion email',
'body' => '<p>Hello {{CUSTOMER_NAME}}</p>',
'subject' => 'Your service report',
'from_email' => 'service@example.test',
'is_default' => '0',
'type' => '1',
]);
Example response
{"ok":1}
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"missing or invalid parameter: id"} | id is absent or converts below 1. |
{"error":"email template does not exist"} | No template has the numeric ID. |
{"error":"subject too long. max length 100"} | The trimmed subject exceeds 100 bytes. |
{"error":"no name parameter"} | The trimmed name is blank. |
{"error":"from_email should be an email address"} | Neither the submitted sender nor the tenant fallback is a syntactically valid email address. |
{"error":"cannot save because that name is already used by another template"} | Another template, including an archived one, has the same name. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Although only
idhas an explicit presence check, the implementation directly readsname,body,subject,from_email, andis_default. Treat all five as required to avoid runtime warnings and unintended blank values. - Every save replaces all template metadata with
{"form_id":...}for type7, or[]for every other type. Unrelated metadata keys are lost. - If the row is changing from non-default to truthy default, all current defaults are cleared first. If the row was already default, the route does not repair any additional rows that are also marked default.
- Inline
data:image...;base64,...images are stored below the tenant’semailtemplate_images/<id>path. Images over twice their HTML width or height are resized to exactly twice both declared dimensions and emitted as PNG. - The final database-update result is not checked; after validation, the endpoint returns success even if that statement fails.
Side effects
- May upload file records/content for inline images, remove unsafe HTML elements, clear other templates’ default flags, and update the selected row.
- This legacy route does not write generic field history or explicitly invalidate the email-template cache.
See it in Fieldmotion
CRM1
Open Settings → Email Templates in CRM1 and filter browser developer tools for the endpoint name. Open a template, edit its fields in the rich-text dialog, and choose Save.
CRM2
Open Settings → Email Templates in CRM2 and filter browser developer tools for the endpoint name. Open a template card, edit it, and save the dialog.
Related endpoints
EmailTemplate_saveDatais nearly identical but permits two sender placeholder codes.EmailTemplate_getreads the stored editor state.