twiliosendgridsendgrid-api-v3

Sendgrid v3 mail/send: Is it possible to send idempotent request?


With SendGrid's v3 API is it possible to send an idempotent request? I'm working on a system that could result in multiple attempts for the same email send so it would be helpful if we could somehow, for instance, pass a unique ID in the request and use the logic of "ignore this request if you've already processed a request with the same unique ID"?


Solution

  • SendGrid's API is not idempotent-safe and will dispatch all POST requests to the Mail Send endpoint at will without any validation for duplicate requests.

    The alternative to avoiding this behaviour is to track which emails have been sent by a unique identifier just as you have requested. SendGrid does not offer any way of keeping a track of delivered identifiers, so you will have to store them yourself in a database.

    What you can do to ensure that you only track the unique identifiers of mail sends that were successful and not invalid is to attach them to the email using unique arguments with each email, these are delivered with the email and can later be received through Event Webhooks.

    Using Custom Arguments

    To attach unique arguments to a mail send, you can attach them to the X-SMTPAPI headers. If you are using the Node.js library, this is achieved by adding a pair of key-value entries to the customArgs field in the mail object:

    const SendGrid = require("@sendgrid/mail");
    SendGrid.setApiKey(SENDGRID_API_KEY);
    
    const Mail = {
        to: "johndoe@email.com",
        from: "company@email.com",
        cc: [],
        subject: "My Email",
        customArgs: {
            unique_id: "YOUR_UNIQUE_IDENTIIFER_HERE"
        }
    }
    
    SendGrid.send(Mail);
    

    Every dispatched email will now contain your unique identifier, for which you can then later track by setting up event webhooks to your endpoint, see Getting Started with the Event Webhook Security Features, there are webhook helpers available in all libraries to make this easier.

    Event Webhook Payload

    You will begin to capture mail events that contain delivery and engagement data, though we are interested in storing our unique identifier.

    Here is an sample webhook payload for the mail "delivered" event:

    [
      {
        "email": "johndoe@email.com",
        "timestamp": 1513299569,
        "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-555>",
        "event": "delivered",
        "ip": "168.1.1.1",
        "category": "cat facts",
        "sg_event_id": "sg_event_id",
        "sg_message_id": "sg_message_id",
        "unique_id": "YOUR_UNIQUE_IDENTIIFER_HERE",
        "response": "250 OK"
      }
    ]
    

    (For other event types, you can see examples here.)

    You'll see that our unique_id is attached within the events related to the mail, this can then be stored in a database and you will have a collection of confirmed mail sends with unique identifiers.

    All that is left to do is to simply query this database with your unique identifier before dispatching emails to ensure that it has not previously been delivered.