4
votes

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

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' => '[email protected]',
        'name' => 'Bob'
    ),
    array(
        'email' => '[email protected]',
        'name' => 'Alice'
    )
);

$mail = new \SendGrid\Mail();

$from = new \SendGrid\Email('myname', '[email protected]');
$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": "[email protected]"
  },
  "personalizations": [
    {
      "to": [
        {
          "email": "[email protected]"
        },
        {
          "email": "[email protected]"
        }
      ],
      "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);
1
Are you using v3 or SMTP? You are referencing SMTP API links but v3 handles things differently. Try this: sendgrid.com/docs/Classroom/Send/v3_Mail_Send/… - bwest
Can you post the JSON payload that the code is generating? - bwest
@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

1 Answers

5
votes

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": "[email protected]"
  },
  "personalizations": [
    {
      "to": [
        {
          "email": "[email protected]"
        }
      ],
      "substitutions": {
        "-name-": "Alice"
      }
    },
    {
      "to": [
        {
          "email": "[email protected]"
        }
      ],
      "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.