sendgrid / sendgrid-nodejs

The Official Twilio SendGrid Led, Community Driven Node.js API Library
https://sendgrid.com
MIT License
3k stars 782 forks source link

Unexpected Error when trying to send transactional email #435

Closed onesien closed 7 years ago

onesien commented 7 years ago

Issue Summary

Getting a 'Bad Request' error with the following payload.

Request

cosnt msg = {
        "to": "ian.reis@gmail.com",
        "from": "invitations@paycheck.fyi",
        "subject": "Support Pay Transparency at PayCheck",
        "templateId": "24ae3147-4faa-4380-8613-c5be144f4542",
        "customArgs": {
            "ally_id": "cj6zlh7yd000001qir4r5suuk"
        }
};
sgMail.send(msg)

Response

{
        "message": "Bad Request",
        "code": 400,
        "response": {
            "headers": {
                "server": "nginx",
                "date": "Wed, 30 Aug 2017 22:30:41 GMT",
                "content-type": "application/json",
                "content-length": "365",
                "connection": "close",
                "access-control-allow-origin": "https://sendgrid.api-docs.io",
                "access-control-allow-methods": "POST",
                "access-control-allow-headers": "Authorization, Content-Type, On-behalf-of, x-sg-elas-acl",
                "access-control-max-age": "600",
                "x-no-cors-reason": "https://sendgrid.com/docs/Classroom/Basics/API/cors.html"
            },
            "body": {
                "errors": [
                    {
                        "message": "Unless a valid template_id is provided, the content parameter is required. There must be at least one defined content block. We typically suggest both text/plain and text/html blocks are included, but only one block is required.",
                        "field": "content",
                        "help": "http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.content"
                    }
                ]
            }
        }
    }

Notes

In the documentation it says templateId but in the error message it says template_id. I've tried both and received the same error message. I attached a screenshot of my template screen as a sanity check to make sure I have it configured correctly in sendgrid.

Technical details:

screen shot 2017-08-30 at 6 43 57 pm

adamreisnz commented 7 years ago

@onesien the new node JS mailer API is case agnostic, so you can use both templateId or template_id. Camel case is more common in JS land, hence we've added support for that, while the API itself consumes snake case.

I'll have a look to see what's happening with the template ID

thinkingserious commented 7 years ago

Hi @onesien,

You might also want to check with support. I think the issue may be related to the old template editor.

Can you also try making a new template and using that ID?

With Best Regards,

Elmer

adamreisnz commented 7 years ago

@thinkingserious can you check this on your end? It does seem like we are correctly sending the template_id parameter with the request. I've just created a new template and am getting this issue as well.

thinkingserious commented 7 years ago

@adamreisnz,

My local tests are working, but I only have new templates on our account.

adamreisnz commented 7 years ago

I will double check

adamreisnz commented 7 years ago

Nope, I used a new template, freshly created, getting the same issue

thinkingserious commented 7 years ago

The following works for me (using version v6.1.1) following the example here:

// Setup sendgrid api
const sendGridMail = require('@sendGrid/mail');
sendGridMail.setApiKey(process.env.SENDGRID_API_KEY);
sendGridMail.setSubstitutionWrappers('-', '-');

//build object 
var mailOptions = {
    personalizations:[{
      to: 'elmer.thomas@sendgrid.com',
      substitutions: {'name':'John', 'city':'Denver'}
    }],
    from: 'dx@sendgrid.com',
    reply_to: 'dx@sendgrid.com',
    subject: 'Hello',
    html: 'email text goes here',
    templateId: '13b8f94f-bcae-4ec6-b752-70d6cb59f932'
  };

//send 
sendGridMail.send(mailOptions);
thinkingserious commented 7 years ago

Ah, I think we have an old bug resurfacing, where the API is requiring a content block in all cases. So this works:

// Setup sendgrid api
const sendGridMail = require('@sendGrid/mail');
sendGridMail.setApiKey(process.env.SENDGRID_API_KEY);
sendGridMail.setSubstitutionWrappers('-', '-');

//build object 
var mailOptions = {
    to: 'elmer.thomas@gmail.com',
    from: 'dx@sendgrid.com',
    reply_to: 'dx@sendgrid.com',
    subject: 'Hello',
    templateId: '13b8f94f-bcae-4ec6-b752-70d6cb59f932',
    html: ' ',
    substitutions: {
      name: 'Some One',
      city: 'Denver',
    }
  };

//send 
sendGridMail.send(mailOptions);

but not this:

// Setup sendgrid api
const sendGridMail = require('@sendGrid/mail');
sendGridMail.setApiKey(process.env.SENDGRID_API_KEY);
sendGridMail.setSubstitutionWrappers('-', '-');

//build object 
var mailOptions = {
    to: 'elmer.thomas@gmail.com',
    from: 'dx@sendgrid.com',
    reply_to: 'dx@sendgrid.com',
    subject: 'Hello',
    templateId: '13b8f94f-bcae-4ec6-b752-70d6cb59f932',
    substitutions: {
      name: 'Some One',
      city: 'Denver',
    }
  };

//send 
sendGridMail.send(mailOptions);
thinkingserious commented 7 years ago

Checking internally...

cbilliau commented 7 years ago

I had to add the content block to get the template to be sent. I was getting a _Bad Request (400) "Unless a valid templateid is provided, the content parameter is required. There must be at least one defined content block..." while using template created in the new html editor.

sgMail.setApiKey(sgKey);
sgMail.setSubstitutionWrappers('-', '-');
var msg: any = {
  to: email,
  from: 'support@freshairsensor.com',
  templateId: 'xxxxxxx',
  substitutions: {
     verifyUrl: createAccountLink
  }
};
sgMail.send(msg)

If I add the content block, the template email is sent as formatted in the html editor.

sgMail.setApiKey(sgKey);
sgMail.setSubstitutionWrappers('-', '-');
var msg: any = {
  to: email,
  from: 'support@freshairsensor.com',
  content: [{"type":"text/html","value":"0"}],
  templateId: 'xxxxxx',
  substitutions: {
     verifyUrl: createAccountLink
  }
};
sgMail.send(msg)
thinkingserious commented 7 years ago

OK, I'm leaving this open as a bug.

My guess is that this SDK is adding an empty content object when it's not set. I think we need to skip these functions when html and txt is not set.

For now, the above workaround will do what you need.

adamreisnz commented 7 years ago

@thinkingserious I think you're right. I read the API docs and thought the field was mandatory. It only has a well hidden comment (which is amazingly styled!) that I missed:

image

I will create a PR to address this!

thinkingserious commented 7 years ago

Hehe, thanks Adam!

adamreisnz commented 7 years ago

PR is up, this should fix the issue and not send the content field with the request if there is no content provided.

onesien commented 7 years ago

Thanks for the help peeps. I was literally losing my mind. I finally figured out a workaround late last night and was coming here to report more information, but it seems like you all are already on it :-)

thinkingserious commented 7 years ago

Sorry about that @onesien,

The fix has just been pushed to npm (v6.1.2).

tetreault commented 6 years ago

I used the code verbatim from the response of @thinkingserious and am still running into issues.

I'm just trying to get the most basic substitutions in a template i created in sengrid to get sent. The response in CloudWatch (since this is running in Lambda) is showing as 202 but the email i receive is: A message was received from this address by our systems that had errors in the smtpapi header, and cannot be processed. The error detected was: The template id must be a valid template id for your account.

What am I doing wrong here guys? I'm trying to sift thru the sendgrid docs but everything feels really piecemeal.

cbilliau commented 6 years ago

How are you sending the template ID? Is it through an environmental variable when the lambda is called?

tetreault commented 6 years ago

thanks for the fast reply @cbilliau -- no in my case the template string is hardcoded since i'm just trying to get the functional scaffolding up between front and back end. My example verbatim is:

const sgMail = require("@sendgrid/mail");
sgMail.setApiKey(
  "XXXXX"
);
sgMail.setSubstitutionWrappers("%", "%"); // Configure the substitution tag wrappers globally
  const msg = {
    to: formFields.toEmail,
    from: formFields.fromEmail,
    subject: "Hello world",
    text: "test",
    html: "<p>test</p>",
    templateId: "be2cc0da-5b2c-428f-8e45-c140f6cfb6eb",
    substitutions: {
      name1: formFields.fromName,
      name2: formFields.fromName,
      date: formFields.date
    }
  };

  sgMail.send(msg);
cbilliau commented 6 years ago

@tetreault Checkout my answer above, I add content: [{"type":"text/html","value":"0"}], to my function and it worked. Unknown why.

tetreault commented 6 years ago

just tried it, unfortunately didn't change the end result @cbilliau :(. Got the same email back:

A message was received from this address by our systems that had errors in the smtpapi header, and cannot be processed. 
The error detected was: The template id must be a valid template id for your account. You provided be2cc0da-5b2c-428f-8e45-c140f6cfb6eb 
tetreault commented 6 years ago

wow let me bow out for a sec @cbilliau 🤣 i just was rushing thru stuff and didn't pay more attention. I realized i was grabbing the unique ID for a template i made under "marketing" but not under "transactional templates". I don't use the sendgrid UI much and just totally botched this one lol

Total face palm, fixing on my end and then hopefully expecting it to work.

tetreault commented 6 years ago

kk - confirming its working now, especially using the content: [{ type: "text/html", value: "0" }] line that @cbilliau mentioned 👍

jwoertink commented 2 years ago

I know this is an old issue, but I'm getting this same error. Using the suggestion by @cbilliau works... The catch here is that I'm not using Javascript... I'm using a Crystal adapter.

These docs say content is required

Screen Shot 2021-11-16 at 3 29 02 PM

so in my case, I was sending an empty array along with the template id {"content": [], "template_id": "abc123"}. If anyone else lands here, {content: [{ type: "text/html", value: "0" }], template_id: "abc123"} works. Possibly also removing the content key if template_id exists, but I haven't been able to test that theory.