DEV Community

Cover image for Fixing Broken Dynamic Links in Email Templates in Dynamics 365 CE
Nikhil Sarpatwari
Nikhil Sarpatwari

Posted on

Fixing Broken Dynamic Links in Email Templates in Dynamics 365 CE

If you've ever used out-of-the-box email templates in Dynamics 365 CE and found that your dynamic links mysteriously break when inserted into an email, you're not alone.

We encountered the same issue: a link that looks perfect in the template ends up half-rendered or malformed when the user sends the email. After digging and testing, we built a reliable workaround. Here’s how we did it, so you can avoid the same frustration.

The Issue

Imagine this scenario:

  • You have an email template with a dynamic URL, like this:
Click <a href="{{custom_url}}">here</a> to view your request.
Enter fullscreen mode Exit fullscreen mode
  • The {{custom_url}} placeholder is supposed to pull from a custom field (e.g., new_urlfield) on the Regarding entity (say, a Case or Opportunity).
  • The template previews fine, but when inserted into a real email, the link breaks. It might look like this:
https://yourdomain.com/cases/34b21290 <some extra text> here
Enter fullscreen mode Exit fullscreen mode

Not ideal.

The Custom Solution: Fix the Email Before It’s Sent

We realized the only reliable way to fix this was to intercept the email just before it’s sent and patch the body ourselves. Here’s the approach:

  1. Use a custom placeholder like {{custom_url}} in the email template instead of standard dynamic fields.
  2. Create a plugin on the Email entity, registered on the Send message.
  3. In the plugin, fetch the Regarding record, grab the real URL, and replace the placeholder.
  4. Save the updated email body just before it’s sent.

Plugin Setup

  • Entity: Email
  • Message: Send
  • Stage: Pre-Operation
  • Mode: Synchronous

This ensures the email hasn’t been sent yet, but all content is available and editable (since it’s still in Draft status).

Sample Plugin Code

Below is the plugin code to fix the email body:

public class FixEmailBeforeSend : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        var service = serviceFactory.CreateOrganizationService(context.UserId);
        var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

        if (context.InputParameters.Contains("EmailId") && context.InputParameters["EmailId"] is EntityReference emailRef)
        {
            var email = service.Retrieve("email", emailRef.Id, new ColumnSet("description", "regardingobjectid"));

            if (email.Contains("description") && email.Contains("regardingobjectid"))
            {
                string body = email.GetAttributeValue<string>("description");
                var regardingRef = email.GetAttributeValue<EntityReference>("regardingobjectid");

                if (body.Contains("{{custom_url}}") && regardingRef != null)
                {
                    var regarding = service.Retrieve(regardingRef.LogicalName, regardingRef.Id, new ColumnSet("new_urlfield"));
                    string url = regarding.GetAttributeValue<string>("new_urlfield");

                    if (!string.IsNullOrWhiteSpace(url))
                    {
                        string updatedBody = body.Replace("{{custom_url}}", url);

                        var updatedEmail = new Entity("email", email.Id)
                        {
                            ["description"] = updatedBody
                        };

                        service.Update(updatedEmail);
                    }
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Testing the Fix

To verify the solution works:

  1. Create a new email using the template with the {{custom_url}} placeholder.
  2. Ensure the email’s Regarding field is set to a record with a URL in new_urlfield.
  3. Send the email.
  4. Check the sent email to confirm the placeholder was replaced with a valid, clickable link.

Why This Works

  • Templates are applied after the email is created, so PreCreate plugins don’t help.
  • The email body is only editable in Draft status, so PostCreate async plugins risk race conditions.
  • The Send message is the last point where everything is in place, and the content can still be modified.

Extending the Pattern

Want to take it further? You can:

  • Support multiple placeholders like {{customer_name}}, {{case_number}}, etc.
  • Load values dynamically from related entities.
  • Create a config entity so business users can manage placeholders without developer intervention.

Wrap-Up

If you're facing broken links in Dynamics 365 CE email templates, you’re not doing anything wrong—it’s a limitation in how the platform handles dynamic fields in HTML. This plugin approach gives you full control, ensuring emails are clean, professional, and functional.


Top comments (0)