Repository: firebase/firebase-admin-go (go)

Issue:
FR: add IsInvalidEmail or publicize internal.FirebaseError
### My environment

  * Operating System version: macOS Catalina 10.15.1
  * Firebase SDK version: v3.9.0
  * Library version: v3.9.0
  * Firebase Product: auth

### The problem

If I add a new user with malformed email address (e.g. `foo..bar@example.com`, `..` is not allowed by RFC) to Firebase Authentication, I get `INVALID_EMAIL` error.
I want to handle this error, but `IsInvalidEmail` is not in the [auth package](https://godoc.org/firebase.google.com/go/auth) and there is no way to get the error code.

```go
package main

import (
	"context"
	"log"

	firebase "firebase.google.com/go"
	"firebase.google.com/go/auth"
	"google.golang.org/api/option"
)

func main() {
	ctx := context.Background()
	opt := option.WithCredentialsFile("serviceAccountKey.json")
	app, err := firebase.NewApp(ctx, nil, opt)
	if err != nil {
		panic(err)
	}
	authClient, err := app.Auth(ctx)
	if err != nil {
		panic(err)
	}

	param := &auth.UserToCreate{}
	param.Email("foo..bar@example.com") // malformed email address `..` is not allowed.
	_, err = authClient.CreateUser(ctx, param)
	log.Println(err)
	log.Printf("%#v", err)

	// I want to handle INVALID_EMAIL error here.
}
```

```
2019/11/05 14:39:20 http error status: 400; body: {
  "error": {
    "code": 400,
    "message": "INVALID_EMAIL",
    "errors": [
      {
        "message": "INVALID_EMAIL",
        "domain": "global",
        "reason": "invalid"
      }
    ]
  }
}

2019/11/05 14:39:20 &internal.FirebaseError{Code:"unknown-error", String:"http error status: 400; body: {\n  \"error\": {\n    \"code\": 400,\n    \"message\": \"INVALID_EMAIL\",\n    \"errors\": [\n      {\n        \"message\": \"INVALID_EMAIL\",\n        \"domain\": \"global\",\n        \"reason\": \"invalid\"\n      }\n    ]\n  }\n}\n"}
```

I want Firebase Admin SDK to add `IsInvalidEmail` function or publicize `internal.FirebaseError`.
How do you think about it?


Pull request:
feat(auth): add auth.IsInvalidEmail function, fixes #295
I added new `IsInvalidEmail` function to handle `INVALID_EMAIL` error.
It fixes #295

RELEASE NOTE: Added a new `IsInvalidEmail()` error checking function.

Patch:
diff --git a/auth/user_mgt.go b/auth/user_mgt.go
index d5b430b..a756a49 100644
--- a/auth/user_mgt.go
+++ b/auth/user_mgt.go
@@ -320,6 +320,7 @@ const (
 	idTokenRevoked           = "id-token-revoked"
 	insufficientPermission   = "insufficient-permission"
 	invalidDynamicLinkDomain = "invalid-dynamic-link-domain"
+	invalidEmail             = "invalid-email"
 	phoneNumberAlreadyExists = "phone-number-already-exists"
 	projectNotFound          = "project-not-found"
 	sessionCookieRevoked     = "session-cookie-revoked"
@@ -354,6 +355,11 @@ func IsInvalidDynamicLinkDomain(err error) bool {
 	return internal.HasErrorCode(err, invalidDynamicLinkDomain)
 }
 
+// IsInvalidEmail checks if the given error was due to an invalid email.
+func IsInvalidEmail(err error) bool {
+	return internal.HasErrorCode(err, invalidEmail)
+}
+
 // IsPhoneNumberAlreadyExists checks if the given error was due to a duplicate phone number.
 func IsPhoneNumberAlreadyExists(err error) bool {
 	return internal.HasErrorCode(err, phoneNumberAlreadyExists)
@@ -396,6 +402,7 @@ var serverError = map[string]string{
 	"EMAIL_EXISTS":                emailAlreadyExists,
 	"INSUFFICIENT_PERMISSION":     insufficientPermission,
 	"INVALID_DYNAMIC_LINK_DOMAIN": invalidDynamicLinkDomain,
+	"INVALID_EMAIL":               invalidEmail,
 	"PERMISSION_DENIED":           insufficientPermission,
 	"PHONE_NUMBER_EXISTS":         phoneNumberAlreadyExists,
 	"PROJECT_NOT_FOUND":           projectNotFound,


Test patch:
diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go
index 247296c..e7b07b5 100644
--- a/auth/user_mgt_test.go
+++ b/auth/user_mgt_test.go
@@ -1187,6 +1187,7 @@ func TestHTTPErrorWithCode(t *testing.T) {
 		"DUPLICATE_LOCAL_ID":      IsUIDAlreadyExists,
 		"EMAIL_EXISTS":            IsEmailAlreadyExists,
 		"INSUFFICIENT_PERMISSION": IsInsufficientPermission,
+		"INVALID_EMAIL":           IsInvalidEmail,
 		"PHONE_NUMBER_EXISTS":     IsPhoneNumberAlreadyExists,
 		"PROJECT_NOT_FOUND":       IsProjectNotFound,
 	}