NodeJS Gmail API email sending fails with 400 error - missing recipient

I’m trying to send emails through Gmail API using native NodeJS HTTPS module and getting a 400 error saying recipient address is required. Here’s my approach:

var message = (
  "Content-Type: text/plain; charset=\"UTF-8\"\n" +
  "MIME-Version: 1.0\n" +
  "to: [email protected]\n" +
  "from: \"My App\" <[email protected]>\n" +
  "subject: Test Message\n\n" +
  "This is the email content"
);

function deliverEmail(accessToken) {
  return new Promise((resolve, reject) => {
    var encodedMessage = Buffer.from(message).toString('base64');
    var urlSafeEncoded = encodedMessage.replace(/\+/g, '-').replace(/\//g, '_');
    
    var requestBody = {
      "raw": urlSafeEncoded
    };
    
    var requestOptions = {
      hostname: 'www.googleapis.com',
      path: '/gmail/v1/users/me/messages/send',
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json'
      }
    };
    
    const request = https.request(requestOptions, (response) => {
      let responseData = '';
      response.on('data', (chunk) => {
        responseData += chunk;
      });
      response.on('end', () => {
        console.log(responseData);
      });
    });
    
    request.on('error', (error) => {
      console.error(error);
    });
    
    request.write(JSON.stringify(requestBody));
    request.end();
  });
}

The base64url encoding seems correct because it works in the API explorer, but my POST request structure must be wrong. What’s the proper way to format the request body for Gmail API without using client libraries?

Double-check your base64 encoding - you’re probably missing the padding removal step. That message format looks wrong too. Add proper MIME boundaries and check for trailing whitespace in your headers. I ran into the same thing because I didn’t escape special characters in the email addresses properly.

Your promise handling is broken - you’re not checking the response status code. Gmail API sends 400 errors in the response body, but your code assumes every response is successful. I hit this same issue building email automation last year. Check response.statusCode in your handler and parse the JSON error message. Also double-check your base64 URL encoding - some characters still cause problems even after the replace operations. Your message structure looks fine, but since the Promise never resolves or rejects properly, you’re probably missing the actual error details from Google’s servers.

Had this exact problem last month building a notification system. It’s your message formatting - Gmail API is picky about RFC 2822 compliance. Your headers need proper line endings.

Switch to \r\n instead of \n for line breaks and add a blank line between headers and body. Also strip padding characters (=) from your base64url encoding. Even tiny formatting issues trigger that 400 error, even when the same message works fine in API explorer.

Double-check your access token has the right Gmail send scope too. The API gives misleading errors when permissions aren’t right.