4

I want to send personalized emails with SendGrid. The whole body is similar, it's just 3-4 one-word-substitions in each mail, so I thought of using SendGrid substitutions

  • Bob (bob@example.com) should get an Email saying "Hi Bob, lorem ipsum"
  • Alice (alice@example.com) should get an Email saying "Hi Alice, lorem ipsum"

The environment is a CodeIgniter-Installation using the provided PHP-Class installed by composer.

The problematic function call is addSubstitution($key, $value), which leads to an error 400 (Bad Request). When submitting the requests without this call, everything works as expected (including my placeholders not substituted of course). I'm getting a clean 202, the emails are arriving. The error text provided by SendMail is {"errors":[{"message":"Bad Request","field":null,"help":null}]} which does not help much.

I thought of adding an array of values to the substitution key. This is copied from this and this code (using the SMTP API in the first example, unclear what in the second), but it seems, that the value of addSubstitution can only handle strings.

To be clear: I need this functionality in it's generic approach. My problem does not only concern the recipients names in the greeting, also a personalized unsubscribe link etc. I'm adding this hint because an answer like "use the Sendgrid-Marketing-API and upload your recipients in before" does not serve my needs.

My PHP script (light version):

// General

$sg = new \SendGrid('api_key');

$recipients = array(
    array(
        'email' => 'bob@example.com',
        'name' => 'Bob'
    ),
    array(
        'email' => 'alice@example.com',
        'name' => 'Alice'
    )
);

$mail = new \SendGrid\Mail();

$from = new \SendGrid\Email('myname', 'myname@mycompany.com');
$mail->setFrom($from);

$mail->setSubject('New mail');

$content = new \SendGrid\Content('text/plain', 'Hi -name-, lorem ipsum');
$mail->addContent($content);

// Personalizations
$personalization = new \SendGrid\Personalization();

$substitutions_name = array();

foreach ($recipients as $recipient) {
    $email = new \SendGrid\Email(null, $recipient['email']);
    $personalization->addTo($email);
    array_push($substitutions_name, $recipient['name']);
}

$personalization->addSubstitution('-name-', $substitutions_name);

$mail->addPersonalization($personalization);

$response = $sg->client->mail()->send()->post($mail);

Is my approach generally wrong? Is there another similar functionality in SendGrid which serves my needs?

Calling the SMTP-API, which seems to have the needed functionality, is no alternative as I don't want call php mail() in fast and long loops.

Update: As I am digging deeper and deeper my solution should work perfectly. This SO answer has exactly the same approach. But why am I still getting the 400-error? The rest of the code works, as a simple try without the substitution-part shows.

Edit: The resulting JSON of the PHP-Script

{
  "from": {
    "name": "myname",
    "email": "myname@mycompany.com"
  },
  "personalizations": [
    {
      "to": [
        {
          "email": "bob@example.com"
        },
        {
          "email": "alice@example.com"
        }
      ],
      "substitutions": {
        "-name-": [
          "Bob",
          "Alice"
        ]
      }
    }
  ],
  "subject": "New mail",
  "content": [
    {
      "type": "text/plain",
      "value": "Hi -name-, lorem ipsum"
    }
  ]
}

Update: Following bwests answer this is the solution for my problem (tested):

[...]

$content = new \SendGrid\Content('text/plain', 'Hi -name-, lorem ipsum');
$mail->addContent($content);

foreach ($recipients as $recipient) {
    $personalization = new \SendGrid\Personalization();
    $email = new \SendGrid\Email(null, $recipient['email']);
    $personalization->addTo($email);
    $personalization->addSubstitution('-name-', $recipient['name']);
    $mail->addPersonalization($personalization);
}

$response = $sg->client->mail()->send()->post($mail);
Community
  • 1
  • 1
Cologne_Muc
  • 653
  • 6
  • 19
  • Are you using v3 or SMTP? You are referencing SMTP API links but v3 handles things differently. Try this: https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html – bwest Nov 02 '16 at 15:56
  • Can you post the JSON payload that the code is generating? – bwest Nov 02 '16 at 15:59
  • @bwest I'm using Web Api v3 but the documentation on this topic (different substitution-values for each recipient) is only found in the SMTP-API docs, therefore my links. Btw: That is also the case for your link. I attached the resulting JSON to my question, any idea?. – Cologne_Muc Nov 02 '16 at 17:45

1 Answers1

5

In v3, substitution values cannot be arrays. Personalizations are different from the legacy SMTP API, though the concepts are the same.

Per this example your payload should look like:

{
  "from": {
    "name": "myname",
    "email": "myname@mycompany.com"
  },
  "personalizations": [
    {
      "to": [
        {
          "email": "alice@example.com"
        }
      ],
      "substitutions": {
        "-name-": "Alice"
      }
    },
    {
      "to": [
        {
          "email": "bob@example.com"
        }
      ],
      "substitutions": {
        "-name-": "Bob"
      }
    }    
  ],
  "subject": "New mail",
  "content": [
    {
      "type": "text/plain",
      "value": "Hi -name-, lorem ipsum"
    }
  ]
}

This change was made to make it easier to look at a single Personalization object and see all of the metadata for that specific email, and to reduce errors that were common due to trying to maintain consistent indices across arrays rather than using structtured data.

bwest
  • 9,182
  • 3
  • 28
  • 58
  • Totally missunderstood the heading of that doc section as my understanding is that we are talking about the same email with different substitutions, not two emails (I'm aware that they technically result in that). Anyway, thats a doc thing. Your solution works, thank you! I will update my question with the final solution for future google searchers. – Cologne_Muc Nov 03 '16 at 08:36
  • 3
    Yeah, I agree that the docs are not good for common use cases. I've let the docs team know and they're gonna take a look. – bwest Nov 03 '16 at 14:01
  • is there any way to add defaul value for substitution? – Adnan Boota Apr 26 '23 at 10:22
  • @AdnanBoota no the expectation if you are making API requests directly is that you can transform the content as needed. The newsletter tool provides default subs. – bwest May 04 '23 at 22:21