diff --git a/NEWS.rst b/NEWS.rst
index 4eba42946578f216bd9ce210fef04607394b4440_TkVXUy5yc3Q=..463b620e40e7dc8398901a7dc8dc563aee3ac475_TkVXUy5yc3Q= 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -2,6 +2,13 @@
 History
 *******
 
+13.0.3.1.0
+==========
+
+(port from 11.0.1.2.0)
+
+* MailTemplate converter: Allow multiple records.
+
 3.0.2
 =====
 
diff --git a/__manifest__.py b/__manifest__.py
index 4eba42946578f216bd9ce210fef04607394b4440_X19tYW5pZmVzdF9fLnB5..463b620e40e7dc8398901a7dc8dc563aee3ac475_X19tYW5pZmVzdF9fLnB5 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -21,7 +21,7 @@
     "name": "Converter",
     "license": "AGPL-3",
     "summary": "Convert odoo records to/from plain data structures.",
-    "version": "13.0.3.0.2",
+    "version": "13.0.3.1.0",
     "category": "Hidden",
     "author": "XCG Consulting",
     "website": "https://odoo.consulting/",
diff --git a/mail_template.py b/mail_template.py
index 4eba42946578f216bd9ce210fef04607394b4440_bWFpbF90ZW1wbGF0ZS5weQ==..463b620e40e7dc8398901a7dc8dc563aee3ac475_bWFpbF90ZW1wbGF0ZS5weQ== 100644
--- a/mail_template.py
+++ b/mail_template.py
@@ -7,8 +7,13 @@
 
 
 class MailTemplate(base.Converter):
+    """This converter wraps ``mail.template::_render_template``.
+    Multiple records are allowed but ``mail.template::render_template`` still
+    runs once per record; to accomodate, we provide ``ctx["records"]``.
+    """
+
     def __init__(self, template: str, post_eval: bool = False):
         self.template = template
         self.post_eval = post_eval
 
     def odoo_to_message(
@@ -10,7 +15,7 @@
     def __init__(self, template: str, post_eval: bool = False):
         self.template = template
         self.post_eval = post_eval
 
     def odoo_to_message(
-        self, instance: models.Model, ctx: Optional[Dict] = None
+        self, records: models.Model, ctx: Optional[Dict] = None
     ) -> Any:
@@ -16,5 +21,8 @@
     ) -> Any:
-        template = instance.env["mail.template"].with_context(safe=True)
-        value = template._render_template(
-            self.template, instance._name, instance.id
+        multiple_records = len(records) > 1
+        record_ids_or_id = records.ids if multiple_records else records.id
+        value = (
+            records.env["mail.template"]
+            .with_context(records=records, safe=True)
+            ._render_template(self.template, records._name, record_ids_or_id)
         )
@@ -20,4 +28,6 @@
         )
+        if multiple_records:  # render_template outputs indexed by record ID
+            value = value[records[0].id]
         if self.post_eval:
             value = ast.literal_eval(value)
         return value
diff --git a/tests/__init__.py b/tests/__init__.py
index 4eba42946578f216bd9ce210fef04607394b4440_dGVzdHMvX19pbml0X18ucHk=..463b620e40e7dc8398901a7dc8dc563aee3ac475_dGVzdHMvX19pbml0X18ucHk= 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -2,5 +2,6 @@
 from . import test_converters  # noqa: F401
 from . import test_field  # noqa: F401
 from . import test_ir_model  # noqa: F401
+from . import test_mail_template  # noqa: F401
 from . import test_relation  # noqa: F401
 from . import test_switch  # noqa: F401
diff --git a/tests/test_mail_template.py b/tests/test_mail_template.py
new file mode 100644
index 0000000000000000000000000000000000000000..463b620e40e7dc8398901a7dc8dc563aee3ac475_dGVzdHMvdGVzdF9tYWlsX3RlbXBsYXRlLnB5
--- /dev/null
+++ b/tests/test_mail_template.py
@@ -0,0 +1,27 @@
+# TODO Copyright notice coming up in further commits.
+
+from odoo import tests
+
+from odoo.addons.converter import MailTemplate
+
+
+class Test(tests.TransactionCase):
+    """Test converter that wraps ``mail.template::_render_template``."""
+
+    def setUp(self):
+        super().setUp()
+        self.user_admin = self.env.ref("base.user_admin")
+        self.user_demo = self.env.ref("base.user_demo")
+
+    def test_mail_template_odoo_to_message(self):
+        converter = MailTemplate("hello ${ object.login }")
+        converted = converter.odoo_to_message(self.user_demo)
+        self.assertEqual(converted, "hello demo")
+
+    def test_mail_template_odoo_to_message_multiple_records(self):
+        converter = MailTemplate(
+            "hello "
+            "${ ' & '.join(ctx['records'].sorted('login').mapped('login')) }"
+        )
+        converted = converter.odoo_to_message(self.user_admin | self.user_demo)
+        self.assertEqual(converted, "hello admin & demo")