@@ -215,6 +215,29 @@ Limitations and quirks
215215 management headers. (The list of allowed custom headers does not seem
216216 to be documented.)
217217
218+ .. _sparkpost-template-limitations :
219+
220+ **Features incompatible with template_id **
221+ When sending with a :attr: `~anymail.message.AnymailMessage.template_id `,
222+ SparkPost doesn't support attachments, inline images, extra headers,
223+ :attr: `!reply_to `, :attr: `!cc ` recipients, or overriding the
224+ :attr: `!from_email `, :attr: `!subject `, or body (text or html) when
225+ sending the message. Some of these can be defined in the template itself,
226+ but SparkPost (often) silently drops them when supplied to their
227+ Transmissions send API.
228+
229+ .. versionchanged :: 11.0
230+
231+ Using features incompatible with :attr: `!template_id ` will raise an
232+ :exc: `~anymail.exceptions.AnymailUnsupportedFeature ` error. In earlier
233+ releases, Anymail would pass the incompatible content to SparkPost's
234+ API, which in many cases would silently ignore it and send the message
235+ anyway.
236+
237+ These limitations only apply when using stored templates (with a template_id),
238+ not when using SparkPost's template language for on-the-fly templating
239+ in a message's subject, body, etc.
240+
218241**Envelope sender may use domain only **
219242 Anymail's :attr: `~anymail.message.AnymailMessage.envelope_sender ` is used to
220243 populate SparkPost's `'return_path' ` parameter. Anymail supplies the full
@@ -246,7 +269,8 @@ and :ref:`batch sending <batch-send>` with per-recipient merge data.
246269You can use a SparkPost stored template by setting a message's
247270:attr: `~anymail.message.AnymailMessage.template_id ` to the
248271template's unique id. (When using a stored template, SparkPost prohibits
249- setting the EmailMessage's subject, text body, or html body.)
272+ setting the EmailMessage's subject, text body, or html body, and has
273+ :ref: `several other limitations <sparkpost-template-limitations >`.)
250274
251275Alternatively, you can refer to merge fields directly in an EmailMessage's
252276subject, body, and other fields---the message itself is used as an
@@ -264,6 +288,7 @@ message attributes.
264288 to = [" alice@example.com" , " Bob <bob@example.com>" ]
265289 )
266290 message.template_id = " 11806290401558530" # SparkPost id
291+ message.from_email = None # must set after constructor (see below)
267292 message.merge_data = {
268293 ' alice@example.com' : {' name' : " Alice" , ' order_no' : " 12345" },
269294 ' bob@example.com' : {' name' : " Bob" , ' order_no' : " 54321" },
@@ -279,6 +304,9 @@ message attributes.
279304 },
280305 }
281306
307+ When using a :attr: `~anymail.message.AnymailMessage.template_id `, you must set the
308+ message's :attr: `!from_email ` to ``None `` as shown above. SparkPost does not permit
309+ specifying the from address at send time when using a stored template.
282310
283311See `SparkPost's substitutions reference `_ for more information on templates and
284312batch send with SparkPost. If you need the special `"dynamic" keys for nested substitutions `_,
0 commit comments