8

I'm using the built-in api for scripting against Google Spreadsheets to send some booking confirmations, and currently my script breaks if someone has filled in an invalid email. I'd like it to just save some data to a list of guests that haven't been notified, and then proceed with looping through the bookings.

This is my current code (simplified):

// The variables email, subject and msg are populated.
// I've tested that using Browser.msgBox(), and the correct column values are
// found and used

// The script breaks here, if an incorrect email address has been filled in
MailApp.sendEmail(email, subject, msg)

According to the documentation the only two methods on the MailApp class are to send emails and check the daily quota - nothing about checking for valid email addresses - so I don't really know what criteria must be fulfilled for the class to accept the request, and thus can't write a validation routine.

Community
  • 1
  • 1
Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • 1
    How about using a simple e-mail validation regex? \b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b – rkg Oct 24 '10 at 16:25
  • @Ravi: I could do something like that, but since the API call breaks on an invalid address, I would very much like to know exactly what criterion the email has to fulfill, and be able to verify that on beforehand... – Tomas Aschan Oct 29 '10 at 17:29
  • Hmm..so does sendEmail throw some specific exception if its an invalid e-mail? – rkg Oct 29 '10 at 19:57
  • 2
    This [Wiki page](http://en.wikipedia.org/wiki/Email_address#Syntax) seems to address this question quite exhaustively. If sendMail fails on any of the 'legally' allowed formats then that should be reported as a feature request. EDIT: You could also do a try-catch around it and store the email address that caused an error. – Anton Soradoi Apr 06 '12 at 21:02

4 Answers4

14

If you need to validate email addresses beforehand, create a blank spreadsheet in your drive. Then, run the function below, changing the testSheet variable to point to the spreadsheet you created. The function will do a simple regex test to catch malformed addresses, then check if the address is actually valid by attempting to temporarily add it as a viewer on the spreadsheet. If the address can be added, it must be valid.

function validateEmail(email) {
  var re = /\S+@\S+\.\S+/;
  if (!re.test(email)) {
    return false;
  } else {
    var testSheet = SpreadsheetApp.openById(arbitrarySpreadsheetInYourDrive);
    try {
      testSheet.addViewer(email);
    } catch(e) {
      return false;
    }
    testSheet.removeViewer(email);
    return true;
  }
}

regex from How to validate email address in JavaScript?

remitnotpaucity
  • 170
  • 1
  • 7
  • 1
    I was thinking of using a similar solution, but I was using the drive service `DriveApp` instead of the spreadsheet service `SpreadhseetApp` and using `DriveApp` service resulted in a notification email being sent to the viewer. However, after looking at [this answer](https://stackoverflow.com/a/29279546/7656369), I found out that the `SpreadsheetApp` does not send the email notification. Good answer! – alejandro Mar 02 '20 at 21:38
  • 1
    You could also create a temporary Spreadsheet, then trash it, rather than leaving a Spreadsheet in Drive just for this purpose. – Janine White Oct 29 '20 at 17:54
6

Stay calm, catch and log the exception and carry on:

try {
  // do stuff, including send email
  MailApp.sendEmail(email, subject, msg)
} catch(e) {
  Logger.log("Error with email (" + email + "). " + e);
}
Peter
  • 5,501
  • 2
  • 26
  • 42
  • This problem is now way old - all the emails I needed to send with that application have already been sent. But if I have to do this again, this is definitely how I'll do it. – Tomas Aschan May 18 '12 at 14:15
  • I think you can't specify the Type of Exception to catch in JavaScript – CaptainNemo Dec 20 '14 at 18:04
  • What kind of exception does this cause? If you send too many emails to invalid emails, you'll be banned. – User Apr 27 '17 at 05:24
  • Problem with this is that other exceptions like `Service invoked too many times for one day: email.` get classified as a bad formatted email address. – User Oct 26 '17 at 16:57
  • Here are some of the exceptions I caught: `Failed to send email: no recipient` and `Invalid email: abc@abc` Also, to avoid quota overload, you can use `MailApp.getRemainingDailyQuota()` – flo5783 May 26 '18 at 18:19
  • Sometimes the script hangs on `Logger.log` — any ideas why? – Vladimir Obrizan Nov 04 '21 at 08:44
0

On the otherhand, avoid Checking email in script and get rid of loses quota or try-catch etc. I used that I got a valid email when user attempt to send an email, by signing him in an email and got that email:

private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
    try {
        GoogleSignInAccount account = completedTask.getResult(ApiException.class);

       String s = account.getEmail(); // here is the valid email.
                       
    } catch (ApiException e) {
        // The ApiException status code indicates the detailed failure reason.
        // Please refer to the GoogleSignInStatusCodes class reference for more information.
        Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
       
    }
}

Full procedure Here.

Noor Hossain
  • 1,620
  • 1
  • 18
  • 25
0

This answer is much later than this question was asked, but I piggy-backed off of remitnotpaucity's answer based on a comment in his answer. It does basically the same thing, adding the email to the spreadsheet and catching the error, however in my case it creates a new spreadsheet, attempts to add the user, and then after attempting to add the user, deletes the spreadsheet. In both cases, that the email is a valid email or not, it deletes the newly created spreadsheet.

Some things to note:

  1. I am not as familiar with regular expressions, so I only check to see if the @ symbol is within the email read into the function, and do not check for whitespaces.
  2. I believe that even if it passes the first if-statement, even if it's not a valid email, an error will still be thrown and caught because Google will still catch that it's not a valid email, making the first if-statement redundant
  3. If you are trying to validate an email outside your company, I'm unsure how it would react, so be fore-warned about that
  4. This validation method takes a few seconds because you are creating and then deleting an email all within a single function, so it takes a fair bit longer than remitnotpaucity's
  5. Most importantly, if you are able to, I would use an API. I believe that this one would work perfectly fine and should be free, it just may take some extra elbow-grease to get to work with GAS.
function validateEmail(email){
    let ss = SpreadsheetApp.openByUrl(SpreadsheetApp.create('Email Validation Spreadsheet', 1, 1).getUrl())
    if(!new RegExp('[@]').test(email)){
      return false
    } else{
      try{
        ss.addViewer(email)
      } catch(e){
        setTrashed()
        return false
      }
      setTrashed()
      return true
    }
    function setTrashed(){
      DriveApp.getFilesByName('Email Validation Spreadsheet').next().setTrashed(true)
    }
  }
Lofton Gentry
  • 189
  • 1
  • 13