2
votes

I am trying to build a REST API in Google Apps Script, that a contacts page shall connect to, that sends emails to me or another point of contact. The Google Script is under my Google Suite account, and thus far, looks like this:

/**
 * Sends contact email, on behalf of the client, to an email of Open Source Roads.
 * @param data - string : a stringified object with the following fields:
 *  - sender
 *  - subject
 *  - message
 *  - recipient
 **/
function sendContactEmail(data) {
  var emailData = JSON.parse(data) || {};
  Logger.log(Object.keys(emailData).length !== 0)
  // if there's no sender, reject it right away
  if ((!emailData.sender) || (typeof(emailData.sender) !== 'string') && (!emailData.sender.email)) throw forbidden('Sender missing');
  // if there's no recipient, reject it right away
  if ((!emailData.recipient) || ((typeof(emailData.recipient) !== 'string') && (!emailData.recipient.email))) throw forbidden('Recipient missing');
  // if there's no subject or message, it's a bad request
  if (!emailData.subject) throw invalidData('Subject missing');
  if (!emailData.message) throw invalidData('Message missing');
  // validate sender,recipient (these will be emails!)
  var sender = retrievePropFrom(emailData, 'sender'),
    recipient= retrievePropFrom(emailData, 'recipient');
  if (!isValidEmail(sender)) throw invalidData("sender must contain a valid email")
  if (!isValidEmail(recipient)) throw invalidData("recipient must contain a valid email")
  // TODO: additional sanitation on emailData.subject,emailData.body?
  // send that email message!
  MailApp.sendEmail(recipient, 
    sender,
    emailData.subject,
    emailData.message
  )
}


function makeError(message, code) { 
  var error = new Error(message);
  error.code = code;
  return error;
}
makeError.FORBIDDEN    = 403;
makeError.UNAUTHORIZED = 401;
makeError.BAD_REQUEST  = 400;

function forbidden(message) { 
  return makeError(message, makeError.FORBIDDEN);
}

function invalidData(message) { 
  return makeError(message, BAD_REQUEST);
}

function isValidEmail(email) { 
  return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(email)
}

/**
 * retrieves the specified property from `obj`. If prop is for either sender or recipient, things get a 
 * little more interesting: 
 * - if the value at the requested `prop` is a string, we return it, like any other `prop`
 * - else if the value at that `prop` contains `email`, we return that
 * 
 **/
function retrievePropFrom(obj, prop) { 
  if (((prop !== "sender")  && (prop !== "recipient")) || (obj[prop] === obj[prop].toString())) 
    return obj[prop];
  if (obj[prop].email) return obj[prop].email;
  return undefined;
}

If I sendContactEmail with myself as the sender and my personal account (different from the owner of the Script) as the recipient, MailApp sends the email message, and I can verify it within seconds. However, when I go to try my actual use case, having the script owning email as recipient and the other email as sender, I get nothing.

I read the documentation, and there's no note that this is a thing. How do I get around this?!

1
This simple example doesn't even work for me: developers.google.com/gmail/markup/apps-script-tutorialMike Warren
Please clarify what the exact issue you encounter istehhowch
I'm able to use the above script to send email to another account as me, but not vice versa. I'm trying to set this script up as an API for sending email to me as the end user (the person who visits my page, fills in the contact form, and clicks "Save")Mike Warren
I tried doing this from PHP, and it also didn't work. It seems there is a problem with my email, such that it's not accepting programmatic email messages. idk how to fix that, let alone what would be causing it. (My email is a GSuite email.)Mike Warren
MailApp always sends email from the Gmail account under whose authority the script is executing - you cannot change or set the sender, only the reply-to. So if they do not authorize your script to run as them (i.e. you publish as a webapp and executing as the user accessing), then you cannot send email from their address. PS: consider editing your question to clearly state your issuetehhowch

1 Answers

2
votes

I was able to resolve the issue.

What was the issue?

The issue, confirmed by attempting to send myself messages by other programmatic means (including myself and another email in the recipients, writing script in PHP) didn't work, meaning it had to be that my domain email wasn't set up properly.

How did you fix it?

So, I hopped on the phone with a GSuite support specialist, and learned that my domain, that my email is under, doesn't have any MX records, let alone any of Google's. I went to the domain provider (in my case, AWS Route 53), and fixed that by adding these MX records:

1 ASPMX.L.GOOGLE.COM.

5 ALT1.ASPMX.L.GOOGLE.COM.

5 ALT2.ASPMX.L.GOOGLE.COM.

10 ALT3.ASPMX.L.GOOGLE.COM.

10 ALT4.ASPMX.L.GOOGLE.COM.

More info here. After doing this and waiting an hour for the network changes to propagate, all the email messages sent through all those times running my script finally reached my email.