sendgrid / email-templates

A repository of common email templates to use and modify to your heart's content.
https://sendgrid.com
MIT License
818 stars 987 forks source link

Dynamic template data for multiple recipients #86

Open JayCunha opened 3 years ago

JayCunha commented 3 years ago

Actual Behaviour

Right now, I can only send dynamic template data for one recipient at a time. Example of my code:

{ "personalizations": [ { "to": [ { "email": "john.doe@example.com", "name": "John Doe" } ], "dynamic_template_data": { "firstName": "John", "lastName": "Doe" }, "subject": "Hello, World!" } ], "from": { "email": "noreply@johndoe.com", "name": "John Doe" }, "reply_to": { "email": "noreply@johndoe.com", "name": "John Doe" }, "template_id": "<>" }

Expected Behaviour

I want to send dynamic template data for each recipient, but I don't know how. The idea is to send personalized e-mails for multiple recipients one at a time, instead of sending emails one by one. I tried to search for an example but I couldn't find it. Do you have any?

hmtanbir commented 3 years ago

Yes, you can send one mail to multiple recipient. I have faced same problem but I have solved the issue. Just use separate personalizations. Example Json:

{
  "personalizations": [
    {
      "to": [
        {
          "email": "john.doe@example.com",
          "name": "John Doe"
        }
      ],
      "dynamic_template_data": {
        "firstName": "John",
        "lastName": "Doe"
      },
      "subject": "Hello, World!"
    },
    {
      "to": [
        {
          "email": "john.doe@example.com",
          "name": "John Doe"
        }
      ],
      "dynamic_template_data": {
        "firstName": "John",
        "lastName": "Doe"
      },
      "subject": "Hello, World!"
    }
  ],
  "from": {
    "email": "noreply@johndoe.com",
    "name": "John Doe"
  },
  "reply_to": {
    "email": "noreply@johndoe.com",
    "name": "John Doe"
  },
  "template_id": "<<YOUR_TEMPLATE_ID>>"
}
logany-hi commented 2 years ago

Since this issue hasn't been closed, how do I inject my dynamic template data into the model when using the SendGridMessage object in C#?

var mail = new SendGridMessage
{
    Attachments = new List<Attachment>(),
    From = new EmailAddress()
    {
        Email = emailConfig.FromAddress,
        Name = emailConfig.FromName
    },
    TemplateId = EmailConstants.ConfirmationEmailTemplateId,
    Subject = subject
};

mail.Personalizations = new List<Personalization>() {
    TemplateData = ???
};
tofy commented 2 years ago

@logany-hi

For you reference:-

public virtual async Task<bool> SendEmailPersonalized<TValue>(Dictionary<string, string> to, string templateId, Dictionary<string, TValue> templateData, string? fromName = null, string? fromEmail = null)
    {
        var msg = new SendGridMessage();
        msg.SetFrom(new EmailAddress(fromEmail ?? sendGridOptions.FromEmail, fromName ?? sendGridOptions.FromName));
        msg.SetTemplateId(templateId);

        msg.Personalizations = new List<Personalization>();

        foreach (var r in to)
        {
            msg.Personalizations.Add(new Personalization()
            {
                Tos = new List<EmailAddress>() { new EmailAddress(r.Key, r.Value) },
                TemplateData = templateData[r.Key]
            }); 
        }

        var response = await sendGridClient.SendEmailAsync(msg);
        if (response.StatusCode >= System.Net.HttpStatusCode.OK && response.StatusCode <= System.Net.HttpStatusCode.IMUsed)
        {
            return true;
        }

        logger.LogWarning("SendEmail returned a negative status. Response: {@response} for {@to} address. TemplateId: {@templateId}", response, to, templateId);
        return false;
    }

//-------------------------------
//Caller of above function
//-------------------------------
foreach (var t in alertsList)
        {
            await _emailService.SendEmailPersonalized(
                t.AlertRecipient.ToDictionary(a => a.Email??Notifications.CommonData.Empty_UserEmail_Replacement, a => a.Name??Notifications.CommonData.Empty_UserName_Replacement)
                ,alertType.TemplateId!
                ,t.AlertRecipient.ToDictionary(a => a.Email?? Notifications.CommonData.Empty_UserEmail_Replacement, a => new CampaignGoalAchieved
                {
                    DonorName = a.Name??Notifications.CommonData.Empty_UserName_Replacement,
                    CampaignName = "Test Campaign Name",
                    CampaignLink = "http://sample.com",
                    GoalAchieved = "25"
                })
                , alertType.Sender
                , alertType.SenderEmail
            );

            t.Status = Notifications.AlertStatus.Processed;
            await UpdateAlertAsync(_Mapper.Map<Alert, AlertDto>(t));
        }
RazGvili commented 1 year ago

I also had issues with it. The docs are pretty disappointing :(

What worked for me - create a separate object for each email. Not using the personalization key.

example:

const yourArrayOfEmails = [{someData: 1, email: 'a@hi.com'}, {someData: 2, email: 'b@hi.com'}]

yourArrayOfEmails.map(emailDetails => {
  return {
    from: {
        email: EMAIL_FROM,
        name: EMAIL_NAME,
    },
    templateId: EMAIL_TEMPLATE_ID,

    // dynamic
    to: emailDetails.email,
    dynamicTemplateData: {
        someData: emailDetails.someData,
    },
  }
})