Skip to content

Commit

Permalink
Add go implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
F21 committed Oct 14, 2019
1 parent 988314c commit 56c4c2c
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 1 deletion.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MailChecker

[![Deps]( https://img.shields.io/david/FGRibreau/mailchecker.svg)](https://david-dm.org/FGRibreau/mailchecker) [![NPM version](https://img.shields.io/npm/v/mailchecker.svg)](http://badge.fury.io/js/mailchecker) [![Gem version](https://img.shields.io/gem/v/ruby-mailchecker.svg)](http://badge.fury.io/js/mailchecker) [![PyPi version](https://img.shields.io/pypi/v/mailchecker.svg)](https://pypi.org/project/mailchecker/#history) [![Packagist version](https://img.shields.io/packagist/v/FGRibreau/mailchecker.svg)](https://packagist.org/packages/fgribreau/mailchecker) [![Cargo version](https://img.shields.io/crates/v/mailchecker.svg)](https://crates.io/crates/mailchecker) [![Downloads](http://img.shields.io/npm/dm/mailchecker.svg)](https://www.npmjs.com/package/mailchecker)
[![Deps]( https://img.shields.io/david/FGRibreau/mailchecker.svg)](https://david-dm.org/FGRibreau/mailchecker) [![NPM version](https://img.shields.io/npm/v/mailchecker.svg)](http://badge.fury.io/js/mailchecker) [![Gem version](https://img.shields.io/gem/v/ruby-mailchecker.svg)](http://badge.fury.io/js/mailchecker) [![PyPi version](https://img.shields.io/pypi/v/mailchecker.svg)](https://pypi.org/project/mailchecker/#history) [![Packagist version](https://img.shields.io/packagist/v/FGRibreau/mailchecker.svg)](https://packagist.org/packages/fgribreau/mailchecker) [![Cargo version](https://img.shields.io/crates/v/mailchecker.svg)](https://crates.io/crates/mailchecker) [![Downloads](http://img.shields.io/npm/dm/mailchecker.svg)](https://www.npmjs.com/package/mailchecker) [![GoDoc](https://godoc.org/github.com/FGRibreau/mailchecker/platform/go?status.svg)](https://godoc.org/github.com/FGRibreau/mailchecker/platform/go)

[![Get help on Codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/francois-guillaume-ribreau?utm_source=github&utm_medium=button&utm_term=francois-guillaume-ribreau&utm_campaign=github) [![available-for-advisory](https://img.shields.io/badge/available%20for%20advising-yes-ff69b4.svg?)](http://bit.ly/2c7uFJq) ![extra](https://img.shields.io/badge/actively%20maintained-yes-ff69b4.svg?)

Expand Down Expand Up @@ -72,6 +72,7 @@ MailChecker currently supports:
* [Rust](https://github.com/FGRibreau/mailchecker/tree/master/platform/rust) ([Instructions](#rust))
* [Elixir](https://github.com/FGRibreau/mailchecker/tree/master/platform/elixir) ([Instructions](#elixir))
* [Clojure](https://github.com/FGRibreau/mailchecker/tree/master/platform/clojure) ([Instructions](#clojure))
* [Go](https://github.com/FGRibreau/mailchecker/tree/master/platform/go) ([Instructions](#go))
* **Easily add support for your own language with MailChecker template system and [send us a pull-request!](https://github.com/FGRibreau/mailchecker/fork_select)**

-------------------------
Expand Down Expand Up @@ -185,11 +186,36 @@ end
(throw (Throwable. "O RLY!")))
```

### Go

```go
package main

import (
"log"

"github.com/FGRibreau/mailchecker/platform/go"
)

if !mail_checker.IsValid('[email protected]') {
log.Fatal('O RLY !');
}

if !mail_checker.IsValid('myemail.com') {
log.Fatal("O RLY !")
}
```

--------------------


## Installation

Go
```bash
go get https://github.com/FGRibreau/mailchecker
```

NodeJS/JavaScript
```bash
npm install mailchecker
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/FGRibreau/mailchecker

go 1.13
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"test": "npm run build && npm-run-all --max-parallel 2 --parallel test:*",
"test:clojure": "echo 'skipping clojure test because it cant handle code too large' || docker run -i -v $(pwd):/app -w /app clojure:lein-2.8.1 lein exec test/platform.clojure.test.clj",
"test:elixir": "docker run -i -v $(pwd):/app -w /app elixir:1.6-slim elixir test/platform.elixir.test.exs",
"test:go": "docker run -i -v $(pwd):/app -w /app golang:1.13-alpine3.10 go test ./...",
"test:node": "mocha --timeout 10000 -r should -R spec -u tdd",
"test:php": "docker run -i -v $(pwd):/app -w /app phpunit/phpunit phpunit test/platform.php.test.php",
"test:python": "docker run -i -v $(pwd):/app -w /app python:2.7-alpine3.7 python test/*.test.py",
Expand Down
56 changes: 56 additions & 0 deletions platform/go/mail_checker.go

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions platform/go/mail_checker.tmpl._go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package mail_checker

import (
"regexp"
"strings"
)

var (
// emailRegex from https://github.com/asaskevich/govalidator as the go regex implementation does not fully support Perl
// syntax: (?!
emailRegex = regexp.MustCompile("^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$")
blacklist = []string{
{{&listSTR}},
}
)

func allDomainSuffixes(domain string) []string {

components := strings.Split(domain, ".")

var result []string

for i := range components {
result = append(result, strings.Join(components[i:], "."))
}

return result
}

// IsValid checks if the email address is a valid email address and is not blacklisted
func IsValid(email string) bool {

email = strings.ToLower(email)

return emailRegex.MatchString(email) && !IsBlacklisted(email)
}

// IsBlacklisted checks if the email address is blacklisted
func IsBlacklisted(email string) bool {

parts := strings.Split(email, "@")

if len(parts) != 2 {
return false
}

for _, domainSuffix := range allDomainSuffixes(parts[1]) {
for _, blacklistedDomain := range blacklist {
if blacklistedDomain == domainSuffix {
return true
}
}
}

return false
}
113 changes: 113 additions & 0 deletions platform/go/mail_checker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package mail_checker

import (
"fmt"
"reflect"
"testing"
)

func TestReturnTrueIfValidEmail(t *testing.T) {
emails := []string{
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
}

for i, email := range emails {
if !IsValid(email) {
t.Errorf("Valid email %x (test case %d) was considered invalid", email, i)
}
}
}

func TestReturnFalseIfEmailInvalid(t *testing.T) {
emails := []string{
"",
" ",
"plopplop.com",
"my+ok@ok=plop.com",
"my,[email protected]",
" [email protected] ",
" [email protected]",
"[email protected] ",
"\n[email protected]\n",
"\n[email protected]",
"[email protected]\n",
}

for i, email := range emails {
if IsValid(email) {
t.Errorf("Invalid email %x (test case %d) was considered valid", email, i)
}
}
}

func TestReturnFalseIfThrowableDomain(t *testing.T) {
emails := []string{
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
}

for i, email := range emails {
if IsValid(email) {
t.Errorf("Email with blacklisted domain %x (test case %d) was considered valid", email, i)
}
}
}

func TestExtractAllDomainSuffixes(t *testing.T) {
testCases := []struct {
domain string
expected []string
}{
{
domain: "sub.example.org",
expected: []string{"sub.example.org", "example.org", "org"},
},
}

for i, testCase := range testCases {
result := allDomainSuffixes(testCase.domain)

if !reflect.DeepEqual(result, testCase.expected) {
t.Errorf("Extracted domain suffixes for %s (test case %d) does not match expected result", testCase.domain, i)
}
}
}

func TestReturnFalseForBlacklistedDomainsAndTheirSubdomains(t *testing.T) {
testCases := []struct {
template string
valid bool
}{
{
template: "test@%s",
valid: false,
},
{
template: "test@subdomain.%s",
valid: false,
},
{
template: "test@%s.gmail.com",
valid: true,
},
}

for i, testCase := range testCases {
for _, blacklistedDomain := range blacklist {

email := fmt.Sprintf(testCase.template, blacklistedDomain)
result := IsValid(email)

if result != testCase.valid {
t.Errorf("Expected result for email %s (test case %d) is %t, got %t", email, i, testCase.valid, result)
}
}
}
}

0 comments on commit 56c4c2c

Please sign in to comment.