MailerSend
Email API

Templates

Use the MailerSend Templates API endpoint to easily manage your transactional email templates. Create, fetch, update, and delete single templates or a list of templates.

Create and manage email templates via the MailerSend API.

Get templates

Retrieve the account templates using this GET request:

GET  https://api.mailersend.com/v1/templates

Request parameters

Query parameterTypeRequiredLimitationsDetails
domain_idstringno
pageintnoMin: 1
limitintnoMin: 10, Max: 100Default: 25
use MailerSend\MailerSend;

$mailersend = new MailerSend(['api_key' => 'key']);

// Get all templates of an account
$mailersend->template->getAll();

// Get all templates of a domain
$mailersend->template->getAll('domain_id');

// Get page 2 of templates with 20 records per page
$mailersend->template->getAll('domain_id', 2, 20);

More examples

import 'dotenv/config';
import { MailerSend} from "mailersend";

const mailerSend = new MailerSend({
  apiKey: process.env.API_KEY,
});

mailerSend.email.template.list({
    domain_id: "domain_id"
})
  .then((response) => console.log(response.body))
  .catch((error) => console.log(error.body));

More examples

from mailersend import MailerSendClient, TemplatesBuilder

ms = MailerSendClient()

request = (TemplatesBuilder()
          .domain_id("domain-id")
          .page(1)
          .limit(25)
          .build_templates_list_request())

response = ms.templates.list_templates(request)

More examples

package main

import (
	"context"
	"log"
	"time"
	
	"github.com/mailersend/mailersend-go"
)

var APIKey = "Api Key Here"

func main() {
	// Create an instance of the mailersend client
	ms := mailersend.NewMailersend(APIKey)

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	
	options := &mailersend.ListTemplateOptions{
		Page:  1,
		Limit: 25,
	}
	
	_, _, err := ms.Template.List(ctx, options)
	if err != nil {
		log.Fatal(err)
	}
}

More examples

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.templates.TemplateItem;
import com.mailersend.sdk.templates.TemplatesList;

public void getTemplatesList() {
    
    MailerSend ms = new MailerSend();
    ms.setToken("mailersend token");
    
    try {
        
            TemplatesList list = ms.templates().getTemplates();
            
            for (TemplateItem item : list.templates) {
                
                System.out.println(item.id);
                System.out.println(item.name);
            }
        
    } catch (MailerSendException e) {
        
        e.printStackTrace();
    }
}

More examples

require "mailersend-ruby"

ms_templates = Mailersend::Templates.new
ms_templates.list(domain_id: "aax455lll", page: 1, limit: 10)

More examples

Responses

Valid

Response Code: 200 OK
Response Headers:
	content-type: application/json
{
  "data": [
      {
        "id": "x8emy5o5world01w",
        "name": "Signup email",
        "description": null,
        "type": "html",
        "image_path": "https://link.com/images/image.jpg",
        "tags": ["transactional", "welcome"],
        "variables": {
          "name": "",
          "company": ""
        },
        "created_at": "2020-06-10 10:09:56",
        "updated_at": "2020-06-10 10:09:56"
      },
      {
        "id": "x8emy5o5world01x",
        "name": "Premium subscription",
        "description": null,
        "type": "html",
        "image_path": "https://link.com/images/image.jpg",
        "tags": [],
        "variables": null,
        "created_at": "2020-06-10 10:09:56",
        "updated_at": "2020-06-10 10:09:56"
      },
      {
        "id": "x8emy5o5world01y",
        "name": "Newsletter",
        "description": null,
        "type": "html",
        "image_path": "https://link.com/images/image.jpg",
        "tags": [],
        "variables": null,
        "created_at": "2020-06-10 10:09:56",
        "updated_at": "2020-06-10 10:09:56"
      }
  ],
  "links": {
    "first": "https:\/\/www.mailersend.io\/api\/v1\/templates?page=1",
    "last": "https:\/\/www.mailersend.io\/api\/v1\/templates?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "path": "https:\/\/www.mailersend.io\/api\/v1\/templates",
    "per_page": 25,
    "to": 3,
    "total": 3
  }
}

Get a single template

Retrieve the information of a single template, its category, domain, and stats using this GET request:

GET https://api.mailersend.com/v1/templates/{template_id}

Request parameters

URL parameterTypeRequiredLimitationsDetails
template_idstringyes
use MailerSend\MailerSend;

$mailersend = new MailerSend(['api_key' => 'key']);

$mailersend->template->find('template_id');

More examples

import 'dotenv/config';
import { MailerSend} from "mailersend";

const mailerSend = new MailerSend({
  apiKey: process.env.API_KEY,
});

mailerSend.email.template.single("template_id")
  .then((response) => console.log(response.body))
  .catch((error) => console.log(error.body));

More examples

from mailersend import MailerSendClient, TemplatesBuilder

ms = MailerSendClient()

request = (TemplatesBuilder()
          .template("template-id")
          .build_template_get_request())

response = ms.templates.get_template(request)

More examples

package main

import (
	"context"
	"log"
	"time"
	
	"github.com/mailersend/mailersend-go"
)

var APIKey = "Api Key Here"

func main() {
	// Create an instance of the mailersend client
	ms := mailersend.NewMailersend(APIKey)

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	
	templateID := "template-id"
	
	_, _, err := ms.Template.Get(ctx, templateID)
	if err != nil {
		log.Fatal(err)
	}
}

More examples

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.MailerSendResponse;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.templates.Template;
import com.mailersend.sdk.templates.TemplateItem;
import com.mailersend.sdk.templates.TemplatesList;

public void getTemplate() {
    
    MailerSend ms = new MailerSend();
    ms.setToken("mailersend token");
    
    try {
        
            Template template = ms.templates().getTemplate("template id");
            
            System.out.println(template.id);
            System.out.println(template.name);
            System.out.println(template.imagePath);
        
    } catch (MailerSendException e) {
        
        e.printStackTrace();
    }
}

More examples

require "mailersend-ruby"

ms_templates = Mailersend::Templates.new
ms_templates.single(template_id: "id124")

More examples

Responses

Valid

{
  "data": {
    "id": "x8emy5o5world01w",
    "name": "libero",
    "description": null,
    "type": "html",
    "image_path": "http://mailersend.com/images/templates/placeholder.png",
    "variables": {
      "name": "",
      "elements": [
        {
          "name": "",
          "price": ""
        }
      ],
      "license_key": "",
      "account_name": "",
      "product_name": "",
      "renew_button": "",
      "expiration_date": ""
    },
    "tags": ["transactional"],
    "created_at": "2021-06-22T15:38:51.000000Z",
    "updated_at": "2021-06-22T16:00:00.000000Z",
    "category": {
      "id": "5genxmqlgozlyvk7",
      "name": "aut"
    },
    "domain": {
      "id": "1jreeo",
      "name": "domain.com",
      "...",
      "domain_settings": {
        "..."
      },
      "totals": {
        "hard_bounced": 25,
        "soft_bounced": 40,
        "sent": 231,
        "delivered": 109
      }
    },
    "template_stats": {
      "total": 1200,
      "queued": 0,
      "sent": 4,
      "rejected": 16,
      "delivered": 1180,
      "delivery_rate": "98",
      "opened": 590,
      "open_rate": "50",
      "clicked": 118,
      "click_rate": "10",
      "unsubscribed": 2,
      "unsubscribe_rate": "0",
      "complained": 0,
      "complain_rate": "0",
      "last_email_sent_at": "2026-10-13T09:30:00.000000Z"
    }
  }
}

Error

Response Code: 404 Not Found

Template stats

template_stats holds the sending stats for the template.

Note

Template stats are all-time totals for the template and can't be filtered by date. They aren't real-time, so a recent send may not show yet. For stats over a date range, tag your emails and use Activity data by date filtered by tag.

FieldTypeDetails
totalintegerAll emails sent with this template, in any status.
queuedintegerEmails waiting to be sent.
sentintegerEmails sent and waiting for a delivery result.
rejectedintegerEmails that could not be delivered.
deliveredintegerEmails delivered.
delivery_ratestring|integerdelivered as a whole-number percentage of total, e.g. "98". 0 when total is 0.
openedintegerDelivered emails opened at least once. Each email counts once.
open_ratestring|integeropened as a whole-number percentage of delivered, e.g. "50". 0 when delivered is 0.
clickedintegerDelivered emails clicked at least once. Each email counts once.
click_ratestring|integerclicked as a whole-number percentage of delivered. 0 when delivered is 0.
unsubscribedintegerEmails whose recipient unsubscribed.
unsubscribe_ratestring|integerunsubscribed as a whole-number percentage of delivered. 0 when delivered is 0.
complainedintegerEmails the recipient marked as spam.
complain_ratestring|integercomplained as a whole-number percentage of delivered. 0 when delivered is 0.
last_email_sent_atstring|nullWhen an email with this template was last sent. null if none has been sent.

Create a template

Create a new template using this POST request:

POST https://api.mailersend.com/v1/templates
use MailerSend\MailerSend;
use MailerSend\Helpers\Builder\TemplateParams;

$mailersend = new MailerSend(['api_key' => 'key']);

$params = (new TemplateParams())
    ->setName('My Template')
    ->setHtml('<p>Hello {{name}}</p>')
    ->setText('Hello {{name}}')
    ->setDomainId('domain_id')
    ->setCategories(['category_id'])
    ->setTags(['transactional', 'welcome']);

$mailersend->template->create($params);

More examples

import 'dotenv/config';
import { MailerSend, EmailTemplate } from "mailersend";

const mailerSend = new MailerSend({
  apiKey: process.env.API_KEY,
});

const template = new EmailTemplate()
  .setName("My Template")
  .setHtml("<p>Hello {{name}}</p>")
  .setText("Hello {{name}}")
  .setDomainId("domain_id")
  .setCategories(["category_id"])
  .setTags(["transactional", "welcome"]);

mailerSend.email.template.create(template)
  .then((response) => console.log(response.body))
  .catch((error) => console.log(error.body));

More examples

from mailersend import MailerSendClient, TemplatesBuilder

ms = MailerSendClient()

request = (TemplatesBuilder()
          .name("My Template")
          .html("<p>Hello {{name}}</p>")
          .text("Hello {{name}}")
          .domain_id("domain-id")
          .categories(["category-id"])
          .tags(["transactional", "welcome"])
          .build_template_create_request())

response = ms.templates.create_template(request)

More examples

package main

import (
	"context"
	"log"
	"time"

	"github.com/mailersend/mailersend-go"
)

var APIKey = "Api Key Here"

func main() {
	// Create an instance of the mailersend client
	ms := mailersend.NewMailersend(APIKey)

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	createOptions := &mailersend.CreateTemplateOptions{
		Name:       "My Template",
		Html:       "<p>Hello {{name}}</p>",
		Text:       "Hello {{name}}",
		DomainID:   "domain-id",
		Categories: []string{"category-id"},
		Tags:       []string{"transactional", "welcome"},
	}

	_, _, err := ms.Template.Create(ctx, createOptions)
	if err != nil {
		log.Fatal(err)
	}
}

More examples

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.templates.Template;

public void createTemplate() {

    MailerSend ms = new MailerSend();
    ms.setToken("mailersend token");

    try {

        Template template = ms.templates().builder()
            .name("My Template")
            .html("<p>Hello {{name}}</p>")
            .text("Hello {{name}}")
            .domainId("domain-id")
            .addCategory("category-id")
            .addTag("transactional")
            .create();

        System.out.println(template.id);
        System.out.println(template.name);

    } catch (MailerSendException e) {

        e.printStackTrace();
    }
}

More examples

require "mailersend-ruby"

ms_templates = Mailersend::Templates.new
ms_templates.create(
  name: "My Template",
  html: "<p>Hello {{name}}</p>",
  text: "Hello {{name}}",
  domain_id: "domain_id",
  categories: ["category_id"],
  tags: ["transactional", "welcome"]
)

More examples

Request parameters

JSON parameters are provided in dot notation

JSON ParameterTypeRequiredLimitationsDetails
htmlstringyesThe HTML body of the template.
textstringyesPlain text version. Auto-generated from HTML if auto_generate is true.
namestringnoMax: 50Defaults to "Template" if not provided.
domain_idstringnoExisting hashed domain ID. Must belong to the account.
categoriesarraynoArray of hashed category IDs. Each must belong to the account.
tagsarraynoMax: 5 items, each max 191 charsArray of tag strings to attach to the template.
auto_generatebooleannoIf true, plain text is auto-generated from the HTML content.

Responses

Valid

Response Code: 201 CREATED
Response Headers:
	content-type: application/json
{
  "data": {
    "id": "x8emy5o5world01w",
    "name": "My Template",
    "description": null,
    "type": "html",
    "image_path": "http://mailersend.com/images/templates/placeholder.png",
    "variables": null,
    "tags": ["transactional", "welcome"],
    "created_at": "2021-06-22T15:38:51.000000Z",
    "updated_at": "2021-06-22T15:38:51.000000Z",
    "category": null,
    "domain": null
  }
}

Invalid

Response Code: 422 Unprocessable Entity

See - Validation errors

Update a template

Update an existing template using this PUT request. Only templates created via API (origin=api) can be updated — templates created in the MailerSend app return 404.

PUT https://api.mailersend.com/v1/templates/{template_id}
use MailerSend\MailerSend;
use MailerSend\Helpers\Builder\TemplateParams;

$mailersend = new MailerSend(['api_key' => 'key']);

$params = (new TemplateParams())
    ->setName('Updated Template Name')
    ->setHtml('<p>Hello {{name}}, your updated content here.</p>')
    ->setText('Hello {{name}}, your updated content here.')
    ->setTags(['transactional']);

$mailersend->template->update('template_id', $params);

More examples

import 'dotenv/config';
import { MailerSend, EmailTemplate } from "mailersend";

const mailerSend = new MailerSend({
  apiKey: process.env.API_KEY,
});

const template = new EmailTemplate()
  .setName("Updated Template Name")
  .setHtml("<p>Hello {{name}}, your updated content here.</p>")
  .setText("Hello {{name}}, your updated content here.")
  .setTags(["transactional"]);

mailerSend.email.template.update("template_id", template)
  .then((response) => console.log(response.body))
  .catch((error) => console.log(error.body));

More examples

from mailersend import MailerSendClient, TemplatesBuilder

ms = MailerSendClient()

request = (TemplatesBuilder()
          .template("template-id")
          .name("Updated Template Name")
          .html("<p>Hello {{name}}, your updated content here.</p>")
          .text("Hello {{name}}, your updated content here.")
          .tags(["transactional"])
          .build_template_update_request())

response = ms.templates.update_template(request)

More examples

package main

import (
	"context"
	"log"
	"time"

	"github.com/mailersend/mailersend-go"
)

var APIKey = "Api Key Here"

func main() {
	// Create an instance of the mailersend client
	ms := mailersend.NewMailersend(APIKey)

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	templateID := "template-id"

	updateOptions := &mailersend.UpdateTemplateOptions{
		Name: "Updated Template Name",
		Html: "<p>Hello {{name}}, your updated content here.</p>",
		Text: "Hello {{name}}, your updated content here.",
		Tags: []string{"transactional"},
	}

	_, _, err := ms.Template.Update(ctx, templateID, updateOptions)
	if err != nil {
		log.Fatal(err)
	}
}

More examples

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.templates.Template;

public void updateTemplate() {

    MailerSend ms = new MailerSend();
    ms.setToken("mailersend token");

    try {

        Template template = ms.templates().builder()
            .name("Updated Template Name")
            .html("<p>Hello {{name}}, your updated content here.</p>")
            .text("Hello {{name}}, your updated content here.")
            .addTag("transactional")
            .update("template-id");

        System.out.println(template.id);
        System.out.println(template.name);

    } catch (MailerSendException e) {

        e.printStackTrace();
    }
}

More examples

require "mailersend-ruby"

ms_templates = Mailersend::Templates.new
ms_templates.update(
  template_id: "template_id",
  name: "Updated Template Name",
  html: "<p>Hello {{name}}, your updated content here.</p>",
  text: "Hello {{name}}, your updated content here.",
  tags: ["transactional"]
)

More examples

Request parameters

URL parameterTypeRequiredLimitationsDetails
template_idstringyes

JSON parameters are provided in dot notation

JSON ParameterTypeRequiredLimitationsDetails
htmlstringnoThe HTML body of the template.
textstringnoPlain text version. Auto-generated from HTML if auto_generate is true.
namestringnoMax: 50
domain_idstringnoExisting hashed domain ID. Must belong to the account.
categoriesarraynoArray of hashed category IDs. Pass an empty array to remove all categories.
tagsarraynoMax: 5 items, each max 191 charsArray of tag strings to attach to the template.
auto_generatebooleannoIf true, plain text is auto-generated from the HTML content.

Responses

Valid

Response Code: 200 OK
Response Headers:
	content-type: application/json
{
  "data": {
    "id": "x8emy5o5world01w",
    "name": "Updated Template Name",
    "description": null,
    "type": "html",
    "image_path": "http://mailersend.com/images/templates/placeholder.png",
    "variables": null,
    "tags": ["transactional"],
    "created_at": "2021-06-22T15:38:51.000000Z",
    "updated_at": "2021-06-22T16:00:00.000000Z",
    "category": null,
    "domain": null
  }
}

Invalid

Response Code: 422 Unprocessable Entity

See - Validation errors

Error

Response Code: 404 Not Found

Delete a template

Delete a template with this DELETE request:

DELETE  https://api.mailersend.com/v1/templates/{template_id}

Request parameters

URL parameterTypeRequiredLimitationsDetails
template_idstringyes
use MailerSend\MailerSend;

$mailersend = new MailerSend(['api_key' => 'key']);

$mailersend->template->delete('template_id');

More examples

import 'dotenv/config';
import { MailerSend} from "mailersend";

const mailerSend = new MailerSend({
  apiKey: process.env.API_KEY,
});

mailerSend.email.template.delete("template_id")
  .then((response) => console.log(response.body))
  .catch((error) => console.log(error.body));

More examples

from mailersend import MailerSendClient, TemplatesBuilder

ms = MailerSendClient()

request = (TemplatesBuilder()
          .template("template-id")
          .build_delete_request())

response = ms.templates.delete_template(request)

More examples

package main

import (
	"context"
	"log"
	"time"
	
	"github.com/mailersend/mailersend-go"
)

var APIKey = "Api Key Here"

func main() {
	// Create an instance of the mailersend client
	ms := mailersend.NewMailersend(APIKey)

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	templateID := "template-id"
	
	_, err := ms.Template.Delete(ctx, templateID)
	if err != nil {
		log.Fatal(err)
	}
}

More examples

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.MailerSendResponse;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.templates.Template;
import com.mailersend.sdk.templates.TemplateItem;
import com.mailersend.sdk.templates.TemplatesList;

public void deleteTemplate() {
    
    MailerSend ms = new MailerSend();
    ms.setToken("mailersend token");
    
    try {
        
            MailerSendResponse response = ms.templates().deleteTemplate("template id");
            
            System.out.println(response.responseStatusCode);
        
    } catch (MailerSendException e) {
        
        e.printStackTrace();
    }
}

More examples

require "mailersend-ruby"

ms_templates = Mailersend::Templates.new
ms_templates.delete(template_id: "id124")

More examples

Responses

Valid

Response Code: 200 OK
Response Body: [EMPTY]

Error

Response Code: 404 Not Found

Email Survey Templates

Using our drag-and-drop email builder, you may create email templates with a survey block to ask questions and reviews to your recipients. When your recipient receives an email with a survey, they can preview the email and answer your survey questions. Then the responses are sent to your webhook if available.

When a recipient answers all available survey questions the responses are immediately sent to your webhook(if available). However, when a recipient doesn't completely answer all available questions, after an idle time of 30 minutes, the responses would be sent.

Rules and steps for sending an email with a survey include:

  • You cannot use the following variables {{url}}, {{survey}}, {{survey_last_question}}, as they are reserved.
  • You must enable content_tracking on your domain by selecting your domain and enabling the setting under tracking details. Content tracking is a feature available on Starter plans and above.
  • Add a webhook with the activity.survey_submitted event to receive the survey answers.
  • You can also include the activity.survey_opened event in your webhook to know when a recipient has opened an email containing a survey at least once.

Payloads

Example of activity.survey_submitted data sent to your webhook:

{
    "type": "activity.survey_submitted",
    "created_at": "2025-08-06T00:20:36.589903Z",
    "data": {
        "id": "68929fd47f916891ef12eba9",
        "domain_id": "7nxe3yjmeq28vp0k",
        "message_id": "68929fd402fd7079a02cf858",
        "email_id": "68929fd47f916891ef12eba9",
        "type": "survey_submitted",
        "subject": "Test email",
        "from": "test@domain.com",
        "tags": [
            "test2",
            "test3"
        ],
        "meta": {
            "surveys": [
                {
                    "question_id": 1,
                    "survey_id": 1,
                    "answer": "test",
                    "is_last_question": true
                }
            ]
        }
    }
}

On this page