├── .generate_coverage.sh ├── .gitignore ├── .travis.yml ├── .update_disposable_list.sh ├── LICENSE ├── README.md ├── check.go ├── check_disposable.go ├── check_disposable_test.go ├── check_test.go ├── disposable_list.go ├── mailckd ├── Dockerfile ├── config.go ├── config_test.go ├── main.go ├── main_test.go ├── validation_handler.go └── validation_handler_test.go └── result.go /.generate_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Requires installation of: `github.com/wadey/gocovmerge` 3 | 4 | cd $GOPATH/src/github.com/smancke/mailck 5 | 6 | rm -rf ./cov 7 | mkdir cov 8 | 9 | i=0 10 | for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_test.go' -type d); 11 | do 12 | if ls ${dir}/*.go &> /dev/null; then 13 | go test -v -covermode=atomic -coverprofile=./cov/$i.out ./${dir} 14 | i=$((i+1)) 15 | fi 16 | done 17 | 18 | gocovmerge ./cov/*.out > full_cov.out 19 | rm -rf ./cov 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | 27 | cover.out 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - tip 5 | 6 | services: 7 | - docker 8 | 9 | before_install: 10 | - go get github.com/wadey/gocovmerge 11 | - go get github.com/mattn/goveralls 12 | - go get golang.org/x/tools/cmd/cover 13 | 14 | script: 15 | - go test -v ./... 16 | - go vet ./... 17 | 18 | after_success: 19 | - ./.generate_coverage.sh 20 | - goveralls -coverprofile=full_cov.out -service=travis-ci 21 | - if [ "$TRAVIS_BRANCH" == "master" ]; then 22 | cd mailckd ; 23 | ls ; 24 | GOOS=linux go build -a --ldflags '-linkmode external -extldflags "-static"' .; 25 | ls ; 26 | docker build -t smancke/mailckd . ; 27 | docker login -e="$DOCKER_EMAIL" -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" ; 28 | docker push smancke/mailckd ; 29 | fi -------------------------------------------------------------------------------- /.update_disposable_list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | file=disposable_list.go 4 | 5 | cat > $file <> $file 17 | 18 | 19 | echo >> $file 20 | echo "}" >> $file 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sebastian Mancke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mailck - SMTP mail validation 2 | golang library for email validation 3 | 4 | [![Build Status](https://api.travis-ci.org/smancke/mailck.svg?branch=master)](https://travis-ci.org/smancke/mailck) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/smancke/mailck)](https://goreportcard.com/report/github.com/smancke/mailck) 6 | [![Coverage Status](https://coveralls.io/repos/github/smancke/mailck/badge.svg?branch=master)](https://coveralls.io/github/smancke/mailck?branch=master) 7 | 8 | This library allows you to check if an email address is realy valid: 9 | 10 | * Syntax check 11 | * Blacklist of disposable mailservers (e.g. mailinator.com) 12 | * SMTP mailbox check 13 | 14 | ## Preconditions 15 | Make sure, that the ip address you are calling from is not 16 | black listed. This is e.g. the case if the ip is a dynamic IP. 17 | Also make sure, that you have a correct reverse dns lookup for 18 | your ip address, matching the hostname of your *from* adress. 19 | Alternatively use a SPF DNS record entry matching the host part 20 | of the *from* address. 21 | 22 | In case of a blacklisting, the target mailserver may respond with an `SMTP 554` 23 | or just let you run into a timout. 24 | 25 | ## Usage 26 | 27 | [![GoDoc](https://godoc.org/github.com/smancke/mailck?status.png)](https://godoc.org/github.com/smancke/mailck) 28 | 29 | Do all checks at once: 30 | 31 | ```go 32 | result, _ := mailck.Check("noreply@mancke.net", "foo@example.com") 33 | switch { 34 | 35 | case result.IsValid(): 36 | // valid! 37 | // the mailserver accepts mails for this mailbox. 38 | 39 | case result.IsError(): 40 | // something went wrong in the smtp communication 41 | // we can't say for sure if the address is valid or not 42 | 43 | case result.IsInvalid(): 44 | // invalid for some reason 45 | // the reason is contained in result.ResultDetail 46 | // or we can check for different reasons: 47 | switch (result) { 48 | case mailck.InvalidDomain: 49 | // domain is invalid 50 | case mailck.InvalidSyntax: 51 | // e-mail address syntax is invalid 52 | } 53 | } 54 | ``` 55 | 56 | ## License 57 | 58 | MIT Licensed 59 | -------------------------------------------------------------------------------- /check.go: -------------------------------------------------------------------------------- 1 | package mailck 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | "net/smtp" 8 | "regexp" 9 | "strings" 10 | ) 11 | 12 | var emailRexp = regexp.MustCompile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}$") 13 | 14 | // Check checks the syntax and if valid, it checks the mailbox by connecting to 15 | // the target mailserver 16 | // The fromEmail is used as from address in the communication to the foreign mailserver. 17 | func Check(fromEmail, checkEmail string) (result Result, err error) { 18 | if !CheckSyntax(checkEmail) { 19 | return InvalidSyntax, nil 20 | } 21 | 22 | if CheckDisposable(checkEmail) { 23 | return Disposable, nil 24 | } 25 | return CheckMailbox(fromEmail, checkEmail) 26 | } 27 | 28 | func CheckWithContext(ctx context.Context, fromEmail, checkEmail string) (result Result, err error) { 29 | if !CheckSyntax(checkEmail) { 30 | return InvalidSyntax, nil 31 | } 32 | 33 | if CheckDisposable(checkEmail) { 34 | return Disposable, nil 35 | } 36 | return CheckMailboxWithContext(ctx, fromEmail, checkEmail) 37 | } 38 | 39 | // CheckSyntax returns true for a valid email, false otherwise 40 | func CheckSyntax(checkEmail string) bool { 41 | return emailRexp.Match([]byte(checkEmail)) 42 | } 43 | 44 | var noContext = context.Background() 45 | var defaultResolver = net.DefaultResolver 46 | var defaultDialer = net.Dialer{} 47 | 48 | // CheckMailbox checks the checkEmail by connecting to the target mailbox and returns the result. 49 | // The fromEmail is used as from address in the communication to the foreign mailserver. 50 | func CheckMailbox(fromEmail, checkEmail string) (result Result, err error) { 51 | mxList, err := net.LookupMX(hostname(checkEmail)) 52 | // TODO: Distinguish between usual network errors 53 | if err != nil || len(mxList) == 0 { 54 | return InvalidDomain, nil 55 | } 56 | return checkMailbox(noContext, fromEmail, checkEmail, mxList, 25) 57 | } 58 | 59 | func CheckMailboxWithContext(ctx context.Context, fromEmail, checkEmail string) (result Result, err error) { 60 | mxList, err := defaultResolver.LookupMX(ctx, hostname(checkEmail)) 61 | // TODO: Distinguish between usual network errors 62 | if err != nil || len(mxList) == 0 { 63 | return InvalidDomain, nil 64 | } 65 | return checkMailbox(ctx, fromEmail, checkEmail, mxList, 25) 66 | } 67 | 68 | type checkRv struct { 69 | res Result 70 | err error 71 | } 72 | 73 | func checkMailbox(ctx context.Context, fromEmail, checkEmail string, mxList []*net.MX, port int) (result Result, err error) { 74 | // try to connect to one mx 75 | var c *smtp.Client 76 | for _, mx := range mxList { 77 | var conn net.Conn 78 | conn, err = defaultDialer.DialContext(ctx, "tcp", fmt.Sprintf("%v:%v", mx.Host, port)) 79 | if t, ok := err.(*net.OpError); ok { 80 | if t.Timeout() { 81 | return TimeoutError, err 82 | } 83 | return NetworkError, err 84 | } else if err != nil { 85 | return MailserverError, err 86 | } 87 | c, err = smtp.NewClient(conn, mx.Host) 88 | if err == nil { 89 | break 90 | } 91 | } 92 | if err != nil { 93 | return MailserverError, err 94 | } 95 | if c == nil { 96 | // just to get very sure, that we have a connection 97 | // this code line should never be reached! 98 | return MailserverError, fmt.Errorf("can't obtain connection for %v", checkEmail) 99 | } 100 | 101 | resChan := make(chan checkRv, 1) 102 | 103 | go func() { 104 | defer c.Close() 105 | defer c.Quit() // defer ist LIFO 106 | // HELO 107 | // err = c.Hello(hostname(fromEmail)) 108 | err = c.Hello(singleMX(fromEmail)) 109 | if err != nil { 110 | resChan <- checkRv{MailserverError, err} 111 | return 112 | } 113 | 114 | // MAIL FROM 115 | err = c.Mail(fromEmail) 116 | if err != nil { 117 | resChan <- checkRv{MailserverError, err} 118 | return 119 | } 120 | 121 | // RCPT TO 122 | id, err := c.Text.Cmd("RCPT TO:<%s>", checkEmail) 123 | if err != nil { 124 | resChan <- checkRv{MailserverError, err} 125 | return 126 | } 127 | c.Text.StartResponse(id) 128 | code, _, err := c.Text.ReadResponse(25) 129 | c.Text.EndResponse(id) 130 | if code == 550 { 131 | resChan <- checkRv{MailboxUnavailable, nil} 132 | return 133 | } 134 | 135 | if err != nil { 136 | resChan <- checkRv{MailserverError, err} 137 | return 138 | } 139 | 140 | resChan <- checkRv{Valid, nil} 141 | 142 | }() 143 | select { 144 | case <-ctx.Done(): 145 | return TimeoutError, ctx.Err() 146 | case q := <-resChan: 147 | return q.res, q.err 148 | } 149 | } 150 | 151 | func hostname(mail string) string { 152 | return mail[strings.Index(mail, "@")+1:] 153 | } 154 | 155 | func singleMX(email string) string { 156 | 157 | var ( 158 | myList string 159 | mxLength int 160 | ) 161 | 162 | domain := email[strings.Index(email, "@")+1:] 163 | mxrecords, _ := net.LookupMX(domain) 164 | 165 | for _, mx := range mxrecords { 166 | 167 | myList = mx.Host 168 | mxLength = len(myList) - 1 169 | } 170 | 171 | return myList[:mxLength] 172 | } -------------------------------------------------------------------------------- /check_disposable.go: -------------------------------------------------------------------------------- 1 | package mailck 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // CheckDisposable returns true if the mail is a disposal mail, false otherwise 8 | func CheckDisposable(checkEmail string) bool { 9 | host := strings.ToLower(hostname(checkEmail)) 10 | return DisposableDomains[host] 11 | } 12 | -------------------------------------------------------------------------------- /check_disposable_test.go: -------------------------------------------------------------------------------- 1 | package mailck 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestCheckDisposable(t *testing.T) { 9 | assert.False(t, CheckDisposable("sebastian@mancke.net")) 10 | assert.True(t, CheckDisposable("foo@mailinator.com")) 11 | } 12 | -------------------------------------------------------------------------------- /check_test.go: -------------------------------------------------------------------------------- 1 | package mailck 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/siebenmann/smtpd" 7 | "github.com/stretchr/testify/assert" 8 | "net" 9 | "testing" 10 | "time" 11 | ) 12 | 13 | func assertResultState(t *testing.T, result Result, expected ResultState) { 14 | assert.Equal(t, result.IsValid(), expected == ValidState) 15 | assert.Equal(t, result.IsInvalid(), expected == InvalidState) 16 | assert.Equal(t, result.IsError(), expected == ErrorState) 17 | } 18 | 19 | func TestCheckSyntax(t *testing.T) { 20 | tests := []struct { 21 | mail string 22 | valid bool 23 | }{ 24 | {"", false}, 25 | {"xxx", false}, 26 | {"s.mancketarent.de", false}, 27 | {"s.mancke@tarentde", false}, 28 | {"s.mancke@tarent@sdc.de", false}, 29 | {"s.mancke@tarent.de", true}, 30 | {"s.Mancke+yzz42@tarent.de", true}, 31 | } 32 | 33 | for _, test := range tests { 34 | t.Run(test.mail, func(t *testing.T) { 35 | result := CheckSyntax(test.mail) 36 | assert.Equal(t, test.valid, result) 37 | }) 38 | } 39 | } 40 | 41 | func TestCheck(t *testing.T) { 42 | tests := []struct { 43 | mail string 44 | result Result 45 | err error 46 | expectedState ResultState 47 | }{ 48 | {"xxx", InvalidSyntax, nil, InvalidState}, 49 | {"s.mancke@sdcsdcsdcsdctarent.de", InvalidDomain, nil, InvalidState}, 50 | {"foo@example.com", InvalidDomain, nil, InvalidState}, 51 | {"foo@mailinator.com", Disposable, nil, InvalidState}, 52 | } 53 | 54 | for _, test := range tests { 55 | t.Run(fmt.Sprintf("regular %v", test.mail), func(t *testing.T) { 56 | start := time.Now() 57 | result, err := Check("noreply@mancke.net", test.mail) 58 | assert.Equal(t, test.result, result) 59 | assert.Equal(t, test.err, err) 60 | assertResultState(t, result, test.expectedState) 61 | fmt.Printf("check for %30v: %-15v => %-10v (%v)\n", test.mail, time.Since(start), test.result.Result, test.result.ResultDetail) 62 | }) 63 | t.Run(fmt.Sprintf("context %v", test.mail), func(t *testing.T) { 64 | start := time.Now() 65 | ctx, cancel := context.WithTimeout(context.Background(), 150*time.Millisecond) 66 | result, err := CheckWithContext(ctx, "noreply@mancke.net", test.mail) 67 | assert.Equal(t, test.result, result) 68 | assert.Equal(t, test.err, err) 69 | assertResultState(t, result, test.expectedState) 70 | assert.WithinDuration(t, time.Now(), start, 160*time.Millisecond) 71 | fmt.Printf("check for %30v: %-15v => %-10v (%v)\n", test.mail, time.Since(start), test.result.Result, test.result.ResultDetail) 72 | cancel() 73 | }) 74 | } 75 | } 76 | 77 | func Test_checkMailbox(t *testing.T) { 78 | tests := []struct { 79 | stopAt smtpd.Command 80 | result Result 81 | expectError bool 82 | expectedState ResultState 83 | }{ 84 | {smtpd.QUIT, Valid, false, ValidState}, 85 | {smtpd.RCPTTO, MailboxUnavailable, false, InvalidState}, 86 | {smtpd.MAILFROM, MailserverError, true, ErrorState}, 87 | {smtpd.HELO, MailserverError, true, ErrorState}, 88 | } 89 | 90 | for _, test := range tests { 91 | t.Run(fmt.Sprintf("stop at: %v", test.stopAt), func(t *testing.T) { 92 | dummyServer := NewDummySMTPServer("localhost:2525", test.stopAt, false, 0) 93 | defer dummyServer.Close() 94 | result, err := checkMailbox(noContext, "noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 2525) 95 | assert.Equal(t, test.result, result) 96 | if test.expectError { 97 | assert.Error(t, err) 98 | } else { 99 | assert.NoError(t, err) 100 | } 101 | assertResultState(t, result, test.expectedState) 102 | }) 103 | } 104 | } 105 | 106 | func Test_checkMailbox_MailserverCloesAfterConnect(t *testing.T) { 107 | dummyServer := NewDummySMTPServer("localhost:2525", smtpd.NOOP, true, 0) 108 | defer dummyServer.Close() 109 | result, err := checkMailbox(noContext, "noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 2525) 110 | assert.Equal(t, MailserverError, result) 111 | assert.Error(t, err) 112 | assertResultState(t, result, ErrorState) 113 | } 114 | 115 | func Test_checkMailbox_NetworkError(t *testing.T) { 116 | result, err := checkMailbox(noContext, "noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 6666) 117 | assert.Equal(t, NetworkError, result) 118 | assert.Error(t, err) 119 | assertResultState(t, result, ErrorState) 120 | } 121 | 122 | func Test_checkMailboxContext(t *testing.T) { 123 | deltas := []struct { 124 | delayTime time.Duration 125 | contextTime time.Duration 126 | expectedResult Result 127 | }{ 128 | {0, 0, TimeoutError}, 129 | {0, time.Second, Valid}, 130 | {time.Millisecond * 1500, 200 * time.Millisecond, TimeoutError}, 131 | } 132 | for _, d := range deltas { 133 | t.Run(fmt.Sprintf("context time %v delay %v expected %v", d.contextTime, d.delayTime, d.expectedResult.Result), func(t *testing.T) { 134 | dummyServer := NewDummySMTPServer("localhost:2528", smtpd.QUIT, false, d.delayTime) 135 | start := time.Now() 136 | ctx, cancel := context.WithTimeout(context.Background(), d.contextTime) 137 | result, err := checkMailbox(ctx, "noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "127.0.0.1"}}, 2528) 138 | if d.expectedResult == Valid { 139 | assert.NoError(t, err) 140 | } else { 141 | assert.Error(t, err) 142 | } 143 | assert.Equal(t, d.expectedResult, result) 144 | // confirm that we completed within requested time 145 | // add 10ms of wiggle room 146 | assert.WithinDuration(t, time.Now(), start, d.contextTime+10*time.Millisecond) 147 | dummyServer.Close() 148 | cancel() 149 | }) 150 | } 151 | } 152 | 153 | type DummySMTPServer struct { 154 | listener net.Listener 155 | running bool 156 | rejectAt smtpd.Command 157 | closeAfterConnect bool 158 | delay time.Duration 159 | } 160 | 161 | func NewDummySMTPServer(listen string, rejectAt smtpd.Command, closeAfterConnect bool, delay time.Duration) *DummySMTPServer { 162 | ln, err := net.Listen("tcp", listen) 163 | if err != nil { 164 | panic(err) 165 | } 166 | time.Sleep(10 * time.Millisecond) 167 | smtpserver := &DummySMTPServer{ 168 | listener: ln, 169 | running: true, 170 | rejectAt: rejectAt, 171 | closeAfterConnect: closeAfterConnect, 172 | delay: delay, 173 | } 174 | 175 | go func() { 176 | for { 177 | conn, err := ln.Accept() 178 | if err != nil { 179 | return 180 | } 181 | if smtpserver.closeAfterConnect { 182 | conn.Close() 183 | } else { 184 | go smtpserver.handleClient(conn) 185 | } 186 | } 187 | }() 188 | time.Sleep(10 * time.Millisecond) 189 | return smtpserver 190 | } 191 | 192 | func (smtpserver *DummySMTPServer) Close() { 193 | smtpserver.listener.Close() 194 | smtpserver.running = false 195 | time.Sleep(10 * time.Millisecond) 196 | } 197 | 198 | func (smtpserver *DummySMTPServer) handleClient(conn net.Conn) { 199 | cfg := smtpd.Config{ 200 | LocalName: "testserver", 201 | SftName: "testserver", 202 | } 203 | c := smtpd.NewConn(conn, cfg, nil) 204 | for smtpserver.running { 205 | event := c.Next() 206 | time.Sleep(smtpserver.delay) 207 | if event.Cmd == smtpserver.rejectAt || 208 | (smtpserver.rejectAt == smtpd.HELO && event.Cmd == smtpd.EHLO) { 209 | c.Reject() 210 | } else { 211 | c.Accept() 212 | } 213 | if event.What == smtpd.DONE { 214 | return 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /disposable_list.go: -------------------------------------------------------------------------------- 1 | package mailck 2 | 3 | // DisposableDomains is a list of fake mail providers. 4 | // The list was taken from https://github.com/andreis/disposable 5 | // License: MIT 6 | // Last updated: Sa 4. Mär 21:33:31 CET 2017 7 | var DisposableDomains = map[string]bool{ 8 | "0-mail.com": true, 9 | "027168.com": true, 10 | "0815.ru": true, 11 | "0815.su": true, 12 | "0clickemail.com": true, 13 | "0wnd.net": true, 14 | "0wnd.org": true, 15 | "10mail.org": true, 16 | "10minutemail.cf": true, 17 | "10minutemail.co.za": true, 18 | "10minutemail.com": true, 19 | "10minutemail.de": true, 20 | "10minutemail.ga": true, 21 | "10minutemail.gq": true, 22 | "10minutemail.ml": true, 23 | "10minutemail.net": true, 24 | "10minutemail.us": true, 25 | "10minutenemail.de": true, 26 | "123-m.com": true, 27 | "12minutemail.com": true, 28 | "1ce.us": true, 29 | "1chuan.com": true, 30 | "1clck2.com": true, 31 | "1mail.ml": true, 32 | "1pad.de": true, 33 | "1up.orangotango.gq": true, 34 | "1zhuan.com": true, 35 | "2-ch.space": true, 36 | "20email.eu": true, 37 | "20mail.in": true, 38 | "20mail.it": true, 39 | "20minute.email": true, 40 | "20minutemail.com": true, 41 | "21cn.com": true, 42 | "225522.ml": true, 43 | "24hourmail.com": true, 44 | "2ch.coms.hk": true, 45 | "2prong.com": true, 46 | "30minutemail.com": true, 47 | "30wave.com": true, 48 | "33mail.com": true, 49 | "3d-painting.com": true, 50 | "3mail.ga": true, 51 | "44556677.igg.biz": true, 52 | "466453.usa.cc": true, 53 | "4mail.cf": true, 54 | "4mail.ga": true, 55 | "4warding.com": true, 56 | "4warding.net": true, 57 | "4warding.org": true, 58 | "5mail.cf": true, 59 | "5mail.ga": true, 60 | "60minutemail.com": true, 61 | "675hosting.com": true, 62 | "675hosting.net": true, 63 | "675hosting.org": true, 64 | "69-ew.tk": true, 65 | "6ip.us": true, 66 | "6mail.cf": true, 67 | "6mail.ga": true, 68 | "6mail.ml": true, 69 | "6paq.com": true, 70 | "6url.com": true, 71 | "75hosting.com": true, 72 | "75hosting.net": true, 73 | "75hosting.org": true, 74 | "7days-printing.com": true, 75 | "7ddf32e.info": true, 76 | "7mail.ga": true, 77 | "7mail.ml": true, 78 | "7tags.com": true, 79 | "7uy35p.tk": true, 80 | "8mail.cf": true, 81 | "8mail.ga": true, 82 | "8mail.ml": true, 83 | "99experts.com": true, 84 | "9mail.cf": true, 85 | "9me.site": true, 86 | "9ox.net": true, 87 | "a-bc.net": true, 88 | "a.betr.co": true, 89 | "a.wxnw.net": true, 90 | "a0.igg.biz": true, 91 | "a1.usa.cc": true, 92 | "a2.flu.cc": true, 93 | "a45.in": true, 94 | "abusemail.de": true, 95 | "abyssmail.com": true, 96 | "ac20mail.in": true, 97 | "acentri.com": true, 98 | "adbet.co": true, 99 | "add3000.pp.ua": true, 100 | "adrianou.gq": true, 101 | "advantimo.com": true, 102 | "afrobacon.com": true, 103 | "ag.us.to": true, 104 | "agedmail.com": true, 105 | "ahk.jp": true, 106 | "ajaxapp.net": true, 107 | "alivance.com": true, 108 | "amail.com": true, 109 | "amilegit.com": true, 110 | "amiri.net": true, 111 | "amiriindustries.com": true, 112 | "anappthat.com": true, 113 | "ano-mail.net": true, 114 | "anon.leemail.me": true, 115 | "anonbox.net": true, 116 | "anonymail.dk": true, 117 | "anonymbox.com": true, 118 | "anonymize.com": true, 119 | "anotherdomaincyka.tk": true, 120 | "antichef.com": true, 121 | "antichef.net": true, 122 | "antispam.de": true, 123 | "antonelli.usa.cc": true, 124 | "apkmd.com": true, 125 | "appixie.com": true, 126 | "armyspy.com": true, 127 | "art-en-ligne.pro": true, 128 | "arur01.tk": true, 129 | "arurgitu.gq": true, 130 | "arurimport.ml": true, 131 | "asdasd.nl": true, 132 | "asiarap.usa.cc": true, 133 | "ass.pp.ua": true, 134 | "aver.com": true, 135 | "avia-tonic.fr": true, 136 | "ay33rs.flu.cc": true, 137 | "azazazatashkent.tk": true, 138 | "azmeil.tk": true, 139 | "b0.nut.cc": true, 140 | "babau.cf": true, 141 | "babau.flu.cc": true, 142 | "babau.ga": true, 143 | "babau.gq": true, 144 | "babau.igg.biz": true, 145 | "babau.ml": true, 146 | "babau.nut.cc": true, 147 | "babau.usa.cc": true, 148 | "bareed.ws": true, 149 | "barryogorman.com": true, 150 | "baxomale.ht.cx": true, 151 | "bccto.me": true, 152 | "bdmuzic.pw": true, 153 | "beddly.com": true, 154 | "beefmilk.com": true, 155 | "belastingdienst.pw": true, 156 | "big1.us": true, 157 | "bigprofessor.so": true, 158 | "bigstring.com": true, 159 | "binka.me": true, 160 | "binkmail.com": true, 161 | "bio-muesli.net": true, 162 | "bione.co": true, 163 | "bladesmail.net": true, 164 | "blogmyway.org": true, 165 | "bloxter.cu.cc": true, 166 | "blutig.me": true, 167 | "bobmail.info": true, 168 | "bodhi.lawlita.com": true, 169 | "bofthew.com": true, 170 | "bongobongo.cf": true, 171 | "bongobongo.flu.cc": true, 172 | "bongobongo.ga": true, 173 | "bongobongo.igg.biz": true, 174 | "bongobongo.ml": true, 175 | "bongobongo.nut.cc": true, 176 | "bongobongo.tk": true, 177 | "bongobongo.usa.cc": true, 178 | "bootybay.de": true, 179 | "boun.cr": true, 180 | "bouncr.com": true, 181 | "boxformail.in": true, 182 | "boximail.com": true, 183 | "boxtemp.com.br": true, 184 | "breadtimes.press": true, 185 | "brefmail.com": true, 186 | "brennendesreich.de": true, 187 | "broadbandninja.com": true, 188 | "browniesgoreng.com": true, 189 | "brownieskukuskreasi.com": true, 190 | "brownieslumer.com": true, 191 | "bsnow.net": true, 192 | "bst-72.com": true, 193 | "btcmail.pw": true, 194 | "bu.mintemail.com": true, 195 | "buffemail.com": true, 196 | "bugmenot.com": true, 197 | "bumpymail.com": true, 198 | "bund.us": true, 199 | "bundes-li.ga": true, 200 | "burnthespam.info": true, 201 | "burstmail.info": true, 202 | "buxap.com": true, 203 | "buyusedlibrarybooks.org": true, 204 | "byom.de": true, 205 | "c.andreihusanu.ro": true, 206 | "c.hcac.net": true, 207 | "c.wlist.ro": true, 208 | "c2.hu": true, 209 | "c4utar.ml": true, 210 | "c51vsgq.com": true, 211 | "cachedot.net": true, 212 | "car101.pro": true, 213 | "cartelera.org": true, 214 | "casualdx.com": true, 215 | "cbair.com": true, 216 | "ce.mintemail.com": true, 217 | "cellurl.com": true, 218 | "centermail.com": true, 219 | "centermail.net": true, 220 | "cetpass.com": true, 221 | "chacuo.net": true, 222 | "chammy.info": true, 223 | "cheatmail.de": true, 224 | "chechnya.conf.work": true, 225 | "chogmail.com": true, 226 | "choicemail1.com": true, 227 | "chong-mail.com": true, 228 | "chong-mail.net": true, 229 | "chong-mail.org": true, 230 | "citroen-c1.ml": true, 231 | "ckaazaza.tk": true, 232 | "clixser.com": true, 233 | "clrmail.com": true, 234 | "clubfier.com": true, 235 | "cmail.com": true, 236 | "cmail.net": true, 237 | "cmail.org": true, 238 | "cnn.coms.hk": true, 239 | "cobarekyo1.ml": true, 240 | "cocodani.cf": true, 241 | "colafanta.cf": true, 242 | "coldemail.info": true, 243 | "consumerriot.com": true, 244 | "contrasto.cu.cc": true, 245 | "cool.fr.nf": true, 246 | "correo.blogos.net": true, 247 | "cosmorph.com": true, 248 | "courriel.fr.nf": true, 249 | "courrieltemporaire.com": true, 250 | "crankmails.com": true, 251 | "crapmail.org": true, 252 | "crazespaces.pw": true, 253 | "crazymailing.com": true, 254 | "cream.pink": true, 255 | "crotslep.ml": true, 256 | "crotslep.tk": true, 257 | "cubiclink.com": true, 258 | "curryworld.de": true, 259 | "cust.in": true, 260 | "cuvox.de": true, 261 | "cx.de-a.org": true, 262 | "cyber-innovation.club": true, 263 | "cyber-phone.eu": true, 264 | "dacoolest.com": true, 265 | "daintly.com": true, 266 | "dandikmail.com": true, 267 | "dasdasdascyka.tk": true, 268 | "dayrep.com": true, 269 | "dbunker.com": true, 270 | "dcemail.com": true, 271 | "de-fake.instafly.cf": true, 272 | "de-fake.webfly.cf": true, 273 | "deadaddress.com": true, 274 | "deadchildren.org": true, 275 | "deadfake.cf": true, 276 | "deadfake.ga": true, 277 | "deadfake.ml": true, 278 | "deadfake.tk": true, 279 | "deadspam.com": true, 280 | "deagot.com": true, 281 | "dealja.com": true, 282 | "despam.it": true, 283 | "despammed.com": true, 284 | "devnullmail.com": true, 285 | "dfgh.net": true, 286 | "dfghj.ml": true, 287 | "dharmatel.net": true, 288 | "digitalsanctuary.com": true, 289 | "dingbone.com": true, 290 | "discard-email.cf": true, 291 | "discard.cf": true, 292 | "discard.email": true, 293 | "discard.ga": true, 294 | "discard.gq": true, 295 | "discard.ml": true, 296 | "discard.tk": true, 297 | "discardmail.com": true, 298 | "discardmail.de": true, 299 | "disign-concept.eu": true, 300 | "disign-revelation.com": true, 301 | "dispomail.eu": true, 302 | "disposable-email.ml": true, 303 | "disposable.cf": true, 304 | "disposable.ga": true, 305 | "disposable.ml": true, 306 | "disposableaddress.com": true, 307 | "disposableemailaddresses.com": true, 308 | "disposableemailaddresses.emailmiser.com": true, 309 | "disposableinbox.com": true, 310 | "dispose.it": true, 311 | "disposeamail.com": true, 312 | "disposemail.com": true, 313 | "dispostable.com": true, 314 | "divermail.com": true, 315 | "divismail.ru": true, 316 | "dlemail.ru": true, 317 | "dm.w3internet.co.uk": true, 318 | "dodgeit.com": true, 319 | "dodgit.com": true, 320 | "dodgit.org": true, 321 | "dodsi.com": true, 322 | "doiea.com": true, 323 | "domforfb1.tk": true, 324 | "domforfb2.tk": true, 325 | "domforfb3.tk": true, 326 | "domforfb4.tk": true, 327 | "domforfb5.tk": true, 328 | "domforfb6.tk": true, 329 | "domforfb7.tk": true, 330 | "domforfb8.tk": true, 331 | "domforfb9.tk": true, 332 | "domozmail.com": true, 333 | "donemail.ru": true, 334 | "dontreg.com": true, 335 | "dontsendmespam.de": true, 336 | "dot-ml.ml": true, 337 | "dot-ml.tk": true, 338 | "dotmsg.com": true, 339 | "dr69.site": true, 340 | "drdrb.com": true, 341 | "drdrb.net": true, 342 | "drivetagdev.com": true, 343 | "droplar.com": true, 344 | "dropmail.me": true, 345 | "duam.net": true, 346 | "dudmail.com": true, 347 | "dump-email.info": true, 348 | "dumpandjunk.com": true, 349 | "dumpmail.de": true, 350 | "dumpyemail.com": true, 351 | "duskmail.com": true, 352 | "dw.now.im": true, 353 | "dx.abuser.eu": true, 354 | "dx.allowed.org": true, 355 | "dx.awiki.org": true, 356 | "dx.ez.lv": true, 357 | "dx.sly.io": true, 358 | "e-mail.com": true, 359 | "e-mail.org": true, 360 | "e.arno.fi": true, 361 | "e.blogspam.ro": true, 362 | "e.discard-email.cf": true, 363 | "e.milavitsaromania.ro": true, 364 | "e.wupics.com": true, 365 | "e0yk-mail.ml": true, 366 | "e4ward.com": true, 367 | "easytrashmail.com": true, 368 | "ecolo-online.fr": true, 369 | "ee2.pl": true, 370 | "eelmail.com": true, 371 | "einrot.com": true, 372 | "einrot.de": true, 373 | "email-fake.cf": true, 374 | "email-fake.ga": true, 375 | "email-fake.gq": true, 376 | "email-fake.ml": true, 377 | "email-fake.tk": true, 378 | "email.cbes.net": true, 379 | "email60.com": true, 380 | "emailage.cf": true, 381 | "emailage.ga": true, 382 | "emailage.gq": true, 383 | "emailage.ml": true, 384 | "emailage.tk": true, 385 | "emaildienst.de": true, 386 | "emailgo.de": true, 387 | "emailias.com": true, 388 | "emailigo.de": true, 389 | "emailinfive.com": true, 390 | "emailisvalid.com": true, 391 | "emaillime.com": true, 392 | "emailmiser.com": true, 393 | "emailproxsy.com": true, 394 | "emails.ga": true, 395 | "emailsensei.com": true, 396 | "emailspam.cf": true, 397 | "emailspam.ga": true, 398 | "emailspam.gq": true, 399 | "emailspam.ml": true, 400 | "emailspam.tk": true, 401 | "emailtemporar.ro": true, 402 | "emailtemporario.com.br": true, 403 | "emailthe.net": true, 404 | "emailtmp.com": true, 405 | "emailto.de": true, 406 | "emailwarden.com": true, 407 | "emailx.at.hm": true, 408 | "emailxfer.com": true, 409 | "emailz.cf": true, 410 | "emailz.ga": true, 411 | "emailz.gq": true, 412 | "emailz.ml": true, 413 | "emeil.in": true, 414 | "emeil.ir": true, 415 | "emil.com": true, 416 | "emkei.cf": true, 417 | "emkei.ga": true, 418 | "emkei.gq": true, 419 | "emkei.ml": true, 420 | "emkei.tk": true, 421 | "eml.pp.ua": true, 422 | "emltmp.com": true, 423 | "emz.net": true, 424 | "enterto.com": true, 425 | "ephemail.net": true, 426 | "eqiluxspam.ga": true, 427 | "erasf.com": true, 428 | "ese.kr": true, 429 | "est.une.victime.ninja": true, 430 | "estate-invest.fr": true, 431 | "etranquil.com": true, 432 | "etranquil.net": true, 433 | "etranquil.org": true, 434 | "eu.igg.biz": true, 435 | "everytg.ml": true, 436 | "evopo.com": true, 437 | "explodemail.com": true, 438 | "eyepaste.com": true, 439 | "ezlo.co": true, 440 | "f5.si": true, 441 | "facebook-email.cf": true, 442 | "facebook-email.ga": true, 443 | "facebook-email.ml": true, 444 | "facebookmail.gq": true, 445 | "facebookmail.ml": true, 446 | "fake-box.com": true, 447 | "fake-email.pp.ua": true, 448 | "fake-mail.cf": true, 449 | "fake-mail.ga": true, 450 | "fake-mail.ml": true, 451 | "fake.i-3gk.cf": true, 452 | "fake.i-3gk.ga": true, 453 | "fake.i-3gk.gq": true, 454 | "fake.i-3gk.ml": true, 455 | "fakeinbox.cf": true, 456 | "fakeinbox.com": true, 457 | "fakeinbox.ga": true, 458 | "fakeinbox.ml": true, 459 | "fakeinbox.tk": true, 460 | "fakeinformation.com": true, 461 | "fakemail.fr": true, 462 | "fakemailgenerator.com": true, 463 | "fakemailz.com": true, 464 | "fammix.com": true, 465 | "fansworldwide.de": true, 466 | "fantasymail.de": true, 467 | "fast-mail.fr": true, 468 | "fastacura.com": true, 469 | "fastchevy.com": true, 470 | "fastchrysler.com": true, 471 | "fastkawasaki.com": true, 472 | "fastmazda.com": true, 473 | "fastmitsubishi.com": true, 474 | "fastnissan.com": true, 475 | "fastsubaru.com": true, 476 | "fastsuzuki.com": true, 477 | "fasttoyota.com": true, 478 | "fastyamaha.com": true, 479 | "fatflap.com": true, 480 | "fbi.coms.hk": true, 481 | "fbmail1.ml": true, 482 | "fdfdsfds.com": true, 483 | "fiat-500.ga": true, 484 | "ficken.de": true, 485 | "fightallspam.com": true, 486 | "fiifke.de": true, 487 | "filzmail.com": true, 488 | "fixmail.tk": true, 489 | "fizmail.com": true, 490 | "flashbox.5july.org": true, 491 | "fleckens.hu": true, 492 | "flemail.ru": true, 493 | "flurred.com": true, 494 | "flyspam.com": true, 495 | "foodbooto.com": true, 496 | "footard.com": true, 497 | "forgetmail.com": true, 498 | "fornow.eu": true, 499 | "forward.cat": true, 500 | "fr33mail.info": true, 501 | "fragolina2.tk": true, 502 | "frapmail.com": true, 503 | "frappina.tk": true, 504 | "frappina99.tk": true, 505 | "free-email.cf": true, 506 | "free-email.ga": true, 507 | "freelance-france.eu": true, 508 | "freemail.ms": true, 509 | "freemail.tweakly.net": true, 510 | "freemails.cf": true, 511 | "freemails.ga": true, 512 | "freemails.ml": true, 513 | "freemeil.ga": true, 514 | "freemeil.gq": true, 515 | "freemeil.ml": true, 516 | "freundin.ru": true, 517 | "friendlymail.co.uk": true, 518 | "front14.org": true, 519 | "fuckingduh.com": true, 520 | "fudgerub.com": true, 521 | "fulvie.com": true, 522 | "fun64.com": true, 523 | "fuwamofu.com": true, 524 | "fux0ringduh.com": true, 525 | "fw.moza.pl": true, 526 | "g.hmail.us": true, 527 | "gamno.config.work": true, 528 | "garliclife.com": true, 529 | "gawab.com": true, 530 | "gelitik.in": true, 531 | "get-mail.cf": true, 532 | "get-mail.ga": true, 533 | "get-mail.ml": true, 534 | "get-mail.tk": true, 535 | "get.pp.ua": true, 536 | "get1mail.com": true, 537 | "get2mail.fr": true, 538 | "getairmail.cf": true, 539 | "getairmail.com": true, 540 | "getairmail.ga": true, 541 | "getairmail.gq": true, 542 | "getairmail.ml": true, 543 | "getairmail.tk": true, 544 | "getmails.eu": true, 545 | "getnada.com": true, 546 | "getonemail.com": true, 547 | "getonemail.net": true, 548 | "ghosttexter.de": true, 549 | "girlsundertheinfluence.com": true, 550 | "gishpuppy.com": true, 551 | "glubex.com": true, 552 | "go.irc.so": true, 553 | "go2usa.info": true, 554 | "godut.com": true, 555 | "goemailgo.com": true, 556 | "goooogle.flu.cc": true, 557 | "goooogle.igg.biz": true, 558 | "goooogle.nut.cc": true, 559 | "goooogle.usa.cc": true, 560 | "gorillaswithdirtyarmpits.com": true, 561 | "gotmail.com": true, 562 | "gotmail.net": true, 563 | "gotmail.org": true, 564 | "gotti.otherinbox.com": true, 565 | "gowikibooks.com": true, 566 | "gowikicampus.com": true, 567 | "gowikicars.com": true, 568 | "gowikifilms.com": true, 569 | "gowikigames.com": true, 570 | "gowikimusic.com": true, 571 | "gowikinetwork.com": true, 572 | "gowikitravel.com": true, 573 | "gowikitv.com": true, 574 | "grandmamail.com": true, 575 | "grandmasmail.com": true, 576 | "great-host.in": true, 577 | "greensloth.com": true, 578 | "grr.la": true, 579 | "gsrv.co.uk": true, 580 | "guerillamail.biz": true, 581 | "guerillamail.com": true, 582 | "guerillamail.net": true, 583 | "guerillamail.org": true, 584 | "guerrillamail.biz": true, 585 | "guerrillamail.com": true, 586 | "guerrillamail.de": true, 587 | "guerrillamail.info": true, 588 | "guerrillamail.net": true, 589 | "guerrillamail.org": true, 590 | "guerrillamailblock.com": true, 591 | "gustr.com": true, 592 | "h.mintemail.com": true, 593 | "h8s.org": true, 594 | "hacccc.com": true, 595 | "haltospam.com": true, 596 | "harakirimail.com": true, 597 | "haribu.net": true, 598 | "hartbot.de": true, 599 | "hasanmail.ml": true, 600 | "hatespam.org": true, 601 | "hellodream.mobi": true, 602 | "herp.in": true, 603 | "hezll.com": true, 604 | "hidemail.de": true, 605 | "hidemail.pro": true, 606 | "hidemail.us": true, 607 | "hidzz.com": true, 608 | "hmamail.com": true, 609 | "hochsitze.com": true, 610 | "hoer.pw": true, 611 | "hopemail.biz": true, 612 | "horvathurtablahoz.ml": true, 613 | "hostcalls.com": true, 614 | "hot-mail.cf": true, 615 | "hot-mail.ga": true, 616 | "hot-mail.gq": true, 617 | "hot-mail.ml": true, 618 | "hot-mail.tk": true, 619 | "hotpop.com": true, 620 | "housat.com": true, 621 | "hstermail.com": true, 622 | "hukkmu.tk": true, 623 | "hulapla.de": true, 624 | "humn.ws.gy": true, 625 | "hunrap.usa.cc": true, 626 | "i.istii.ro": true, 627 | "i.klipp.su": true, 628 | "i.wawi.es": true, 629 | "i.xcode.ro": true, 630 | "i2pmail.org": true, 631 | "ichigo.me": true, 632 | "ieatspam.eu": true, 633 | "ieatspam.info": true, 634 | "ieh-mail.de": true, 635 | "ihateyoualot.info": true, 636 | "ihazspam.ca": true, 637 | "iheartspam.org": true, 638 | "ikbenspamvrij.nl": true, 639 | "imails.info": true, 640 | "imgof.com": true, 641 | "imgv.de": true, 642 | "immo-gerance.info": true, 643 | "imstations.com": true, 644 | "inbax.tk": true, 645 | "inbound.plus": true, 646 | "inbox.si": true, 647 | "inboxalias.com": true, 648 | "inboxbear.com": true, 649 | "inboxclean.com": true, 650 | "inboxclean.org": true, 651 | "inboxproxy.com": true, 652 | "inclusiveprogress.com": true, 653 | "incognitomail.com": true, 654 | "incognitomail.net": true, 655 | "incognitomail.org": true, 656 | "infest.org": true, 657 | "info-radio.ml": true, 658 | "inmynetwork.tk": true, 659 | "insorg-mail.info": true, 660 | "instant-mail.de": true, 661 | "instantemailaddress.com": true, 662 | "instantmail.fr": true, 663 | "ip4.pp.ua": true, 664 | "ip6.pp.ua": true, 665 | "ipoo.org": true, 666 | "irish2me.com": true, 667 | "iroid.com": true, 668 | "isdaq.com": true, 669 | "italia.flu.cc": true, 670 | "italia.igg.biz": true, 671 | "itmtx.com": true, 672 | "itsme.edu.pl": true, 673 | "iwi.net": true, 674 | "jcpclothing.ga": true, 675 | "je-recycle.info": true, 676 | "jet-renovation.fr": true, 677 | "jetable.com": true, 678 | "jetable.fr.nf": true, 679 | "jetable.net": true, 680 | "jetable.org": true, 681 | "jetable.pp.ua": true, 682 | "jnxjn.com": true, 683 | "jobbikszimpatizans.hu": true, 684 | "jourrapide.com": true, 685 | "jp.ftp.sh": true, 686 | "jsrsolutions.com": true, 687 | "junk1e.com": true, 688 | "junkmail.ga": true, 689 | "junkmail.gq": true, 690 | "jwk4227ufn.com": true, 691 | "k.fido.be": true, 692 | "kachadresp.tk": true, 693 | "kanker.website": true, 694 | "kasmail.com": true, 695 | "kaspop.com": true, 696 | "kazelink.ml": true, 697 | "keepmymail.com": true, 698 | "keinpardon.de": true, 699 | "kemska.pw": true, 700 | "killmail.com": true, 701 | "killmail.net": true, 702 | "kimsdisk.com": true, 703 | "kingsq.ga": true, 704 | "kir.ch.tc": true, 705 | "klassmaster.com": true, 706 | "klassmaster.net": true, 707 | "klzlk.com": true, 708 | "knol-power.nl": true, 709 | "kook.ml": true, 710 | "koszmail.pl": true, 711 | "kuatcak.cf": true, 712 | "kuatcak.tk": true, 713 | "kuatmail.gq": true, 714 | "kuatmail.tk": true, 715 | "kulturbetrieb.info": true, 716 | "kurzepost.de": true, 717 | "kusrc.com": true, 718 | "l33r.eu": true, 719 | "labetteraverouge.at": true, 720 | "lackmail.net": true, 721 | "lackmail.ru": true, 722 | "lags.us": true, 723 | "lajoska.pe.hu": true, 724 | "landmail.co": true, 725 | "laoeq.com": true, 726 | "laoho.com": true, 727 | "last-chance.pro": true, 728 | "lastmail.co": true, 729 | "lastmail.com": true, 730 | "lazyinbox.com": true, 731 | "leeching.net": true, 732 | "legalrc.loan": true, 733 | "letthemeatspam.com": true, 734 | "lhsdv.com": true, 735 | "lifebyfood.com": true, 736 | "link2mail.net": true, 737 | "linkedintuts2016.pw": true, 738 | "litedrop.com": true, 739 | "liveradio.tk": true, 740 | "loadby.us": true, 741 | "loan101.pro": true, 742 | "login-email.cf": true, 743 | "login-email.ga": true, 744 | "login-email.ml": true, 745 | "login-email.tk": true, 746 | "loh.pp.ua": true, 747 | "lol.ovpn.to": true, 748 | "lolfreak.net": true, 749 | "lolito.tk": true, 750 | "lookugly.com": true, 751 | "lopl.co.cc": true, 752 | "lortemail.dk": true, 753 | "lovefall.ml": true, 754 | "lovemeleaveme.com": true, 755 | "lovesea.gq": true, 756 | "lr7.us": true, 757 | "lr78.com": true, 758 | "lroid.com": true, 759 | "luv2.us": true, 760 | "m.ddcrew.com": true, 761 | "m4ilweb.info": true, 762 | "maboard.com": true, 763 | "macr2.com": true, 764 | "mail-easy.fr": true, 765 | "mail-filter.com": true, 766 | "mail-temporaire.fr": true, 767 | "mail-tester.com": true, 768 | "mail.backflip.cf": true, 769 | "mail.by": true, 770 | "mail.mezimages.net": true, 771 | "mail.wtf": true, 772 | "mail114.net": true, 773 | "mail2rss.org": true, 774 | "mail333.com": true, 775 | "mail4trash.com": true, 776 | "mailbidon.com": true, 777 | "mailblocks.com": true, 778 | "mailbox72.biz": true, 779 | "mailbox80.biz": true, 780 | "mailbucket.org": true, 781 | "mailcat.biz": true, 782 | "mailcatch.com": true, 783 | "maildrop.cc": true, 784 | "maildrop.cf": true, 785 | "maildrop.ga": true, 786 | "maildrop.gq": true, 787 | "maildrop.ml": true, 788 | "maildx.com": true, 789 | "maileater.com": true, 790 | "mailed.ro": true, 791 | "maileme101.com": true, 792 | "mailexpire.com": true, 793 | "mailfa.tk": true, 794 | "mailforspam.com": true, 795 | "mailfree.ga": true, 796 | "mailfree.gq": true, 797 | "mailfree.ml": true, 798 | "mailfreeonline.com": true, 799 | "mailfs.com": true, 800 | "mailguard.me": true, 801 | "mailhero.io": true, 802 | "mailimate.com": true, 803 | "mailin8r.com": true, 804 | "mailinatar.com": true, 805 | "mailinater.com": true, 806 | "mailinator.com": true, 807 | "mailinator.gq": true, 808 | "mailinator.net": true, 809 | "mailinator.org": true, 810 | "mailinator.us": true, 811 | "mailinator2.com": true, 812 | "mailincubator.com": true, 813 | "mailismagic.com": true, 814 | "mailjunk.cf": true, 815 | "mailjunk.ga": true, 816 | "mailjunk.gq": true, 817 | "mailjunk.ml": true, 818 | "mailjunk.tk": true, 819 | "mailmate.com": true, 820 | "mailme.gq": true, 821 | "mailme.ir": true, 822 | "mailme.lv": true, 823 | "mailme24.com": true, 824 | "mailmetrash.com": true, 825 | "mailmoat.com": true, 826 | "mailnator.com": true, 827 | "mailnesia.com": true, 828 | "mailnull.com": true, 829 | "mailpick.biz": true, 830 | "mailproxsy.com": true, 831 | "mailquack.com": true, 832 | "mailrock.biz": true, 833 | "mailsac.com": true, 834 | "mailscrap.com": true, 835 | "mailseal.de": true, 836 | "mailshell.com": true, 837 | "mailsiphon.com": true, 838 | "mailslapping.com": true, 839 | "mailslite.com": true, 840 | "mailspam.usa.cc": true, 841 | "mailspam.xyz": true, 842 | "mailtemp.info": true, 843 | "mailtome.de": true, 844 | "mailtothis.com": true, 845 | "mailzi.ru": true, 846 | "mailzilla.com": true, 847 | "mailzilla.org": true, 848 | "mailzilla.orgmbx.cc": true, 849 | "makemetheking.com": true, 850 | "manifestgenerator.com": true, 851 | "manybrain.com": true, 852 | "martin.securehost.com.es": true, 853 | "materiali.ml": true, 854 | "mbx.cc": true, 855 | "mciek.com": true, 856 | "mega.zik.dj": true, 857 | "meinspamschutz.de": true, 858 | "meltmail.com": true, 859 | "merda.flu.cc": true, 860 | "merda.igg.biz": true, 861 | "merda.nut.cc": true, 862 | "merda.usa.cc": true, 863 | "merry.pink": true, 864 | "messagebeamer.de": true, 865 | "mezimages.net": true, 866 | "mfsa.ru": true, 867 | "mierdamail.com": true, 868 | "migmail.net": true, 869 | "migmail.pl": true, 870 | "migumail.com": true, 871 | "mintemail.com": true, 872 | "mjukglass.nu": true, 873 | "moakt.com": true, 874 | "moakt.ws": true, 875 | "mobi.web.id": true, 876 | "mobileninja.co.uk": true, 877 | "moburl.com": true, 878 | "mohmal.com": true, 879 | "mohmal.im": true, 880 | "mohmal.in": true, 881 | "mohmal.tech": true, 882 | "moncourrier.fr.nf": true, 883 | "monemail.fr.nf": true, 884 | "monmail.fr.nf": true, 885 | "monumentmail.com": true, 886 | "mor19.uu.gl": true, 887 | "morahdsl.cf": true, 888 | "mox.pp.ua": true, 889 | "mrblacklist.gq": true, 890 | "mrresourcepacks.tk": true, 891 | "ms9.mailslite.com": true, 892 | "msa.minsmail.com": true, 893 | "mt2009.com": true, 894 | "mt2014.com": true, 895 | "mt2015.com": true, 896 | "mt2016.com": true, 897 | "mt2017.com": true, 898 | "muehlacker.tk": true, 899 | "muq.orangotango.tk": true, 900 | "mvrht.com": true, 901 | "mx0.wwwnew.eu": true, 902 | "my.efxs.ca": true, 903 | "my.spam.orangotango.ml": true, 904 | "my10minutemail.com": true, 905 | "mycleaninbox.net": true, 906 | "myemailboxy.com": true, 907 | "mymail-in.net": true, 908 | "mymailoasis.com": true, 909 | "mymailto.cf": true, 910 | "mymailto.ga": true, 911 | "myneocards.cz": true, 912 | "mynetstore.de": true, 913 | "mypacks.net": true, 914 | "mypartyclip.de": true, 915 | "myphantomemail.com": true, 916 | "myspaceinc.com": true, 917 | "myspaceinc.net": true, 918 | "myspaceinc.org": true, 919 | "myspacepimpedup.com": true, 920 | "myspamless.com": true, 921 | "mytemp.email": true, 922 | "mytempemail.com": true, 923 | "mytrashmail.com": true, 924 | "n.ra3.us": true, 925 | "n.spamtrap.co": true, 926 | "n.zavio.nl": true, 927 | "napalm51.cf": true, 928 | "napalm51.flu.cc": true, 929 | "napalm51.ga": true, 930 | "napalm51.gq": true, 931 | "napalm51.igg.biz": true, 932 | "napalm51.ml": true, 933 | "napalm51.nut.cc": true, 934 | "napalm51.tk": true, 935 | "napalm51.usa.cc": true, 936 | "neko2.net": true, 937 | "neomailbox.com": true, 938 | "nepwk.com": true, 939 | "nervmich.net": true, 940 | "nervtmich.net": true, 941 | "netmails.com": true, 942 | "netmails.net": true, 943 | "netzidiot.de": true, 944 | "neverbox.com": true, 945 | "nezzart.com": true, 946 | "nice-4u.com": true, 947 | "nike.coms.hk": true, 948 | "nmail.cf": true, 949 | "no-spam.ws": true, 950 | "nobulk.com": true, 951 | "noclickemail.com": true, 952 | "nogmailspam.info": true, 953 | "nomail.xl.cx": true, 954 | "nomail2me.com": true, 955 | "nomorespamemails.com": true, 956 | "nonspam.eu": true, 957 | "nonspammer.de": true, 958 | "noref.in": true, 959 | "nospam.wins.com.br": true, 960 | "nospam.ze.tc": true, 961 | "nospam4.us": true, 962 | "nospamfor.us": true, 963 | "nospamthanks.info": true, 964 | "notmailinator.com": true, 965 | "notsharingmy.info": true, 966 | "nowhere.org": true, 967 | "nowmymail.com": true, 968 | "ntlhelp.net": true, 969 | "nurfuerspam.de": true, 970 | "nus.edu.sg": true, 971 | "nutpa.net": true, 972 | "nwldx.com": true, 973 | "nwytg.com": true, 974 | "o.cfo2go.ro": true, 975 | "o.oai.asia": true, 976 | "o.opendns.ro": true, 977 | "o.spamtrap.ro": true, 978 | "objectmail.com": true, 979 | "obobbo.com": true, 980 | "odaymail.com": true, 981 | "olypmall.ru": true, 982 | "one-time.email": true, 983 | "oneoffemail.com": true, 984 | "oneoffmail.com": true, 985 | "onewaymail.com": true, 986 | "online.ms": true, 987 | "oopi.org": true, 988 | "opayq.com": true, 989 | "opel-corsa.tk": true, 990 | "opentrash.com": true, 991 | "orango.cu.cc": true, 992 | "ordinaryamerican.net": true, 993 | "oshietechan.link": true, 994 | "otherinbox.com": true, 995 | "ourklips.com": true, 996 | "outlawspam.com": true, 997 | "ovpn.to": true, 998 | "owlpic.com": true, 999 | "p71ce1m.com": true, 1000 | "pagamenti.tk": true, 1001 | "paller.cf": true, 1002 | "pancakemail.com": true, 1003 | "paplease.com": true, 1004 | "parlimentpetitioner.tk": true, 1005 | "password.colafanta.cf": true, 1006 | "pcusers.otherinbox.com": true, 1007 | "pepbot.com": true, 1008 | "pepsi.coms.hk": true, 1009 | "pfui.ru": true, 1010 | "photo-impact.eu": true, 1011 | "phpbb.uu.gl": true, 1012 | "phus8kajuspa.cu.cc": true, 1013 | "pimpedupmyspace.com": true, 1014 | "pjjkp.com": true, 1015 | "plexolan.de": true, 1016 | "po.bot.nu": true, 1017 | "poh.pp.ua": true, 1018 | "pokemail.net": true, 1019 | "politikerclub.de": true, 1020 | "polyfaust.com": true, 1021 | "poofy.org": true, 1022 | "pookmail.com": true, 1023 | "porco.cf": true, 1024 | "porco.ga": true, 1025 | "porco.gq": true, 1026 | "porco.ml": true, 1027 | "postacin.com": true, 1028 | "ppetw.com": true, 1029 | "premium-mail.fr": true, 1030 | "privacy.net": true, 1031 | "privy-mail.com": true, 1032 | "privymail.de": true, 1033 | "project-xhabbo.com": true, 1034 | "proxymail.eu": true, 1035 | "prtnx.com": true, 1036 | "prtz.eu": true, 1037 | "psles.com": true, 1038 | "punkass.com": true, 1039 | "purple.flu.cc": true, 1040 | "purple.igg.biz": true, 1041 | "purple.nut.cc": true, 1042 | "purple.usa.cc": true, 1043 | "puttanamaiala.tk": true, 1044 | "putthisinyourspamdatabase.com": true, 1045 | "pw.flu.cc": true, 1046 | "pw.igg.biz": true, 1047 | "pw.nut.cc": true, 1048 | "pwrby.com": true, 1049 | "q5vm7pi9.com": true, 1050 | "qasti.com": true, 1051 | "qisdo.com": true, 1052 | "qisoa.com": true, 1053 | "qs.dp76.com": true, 1054 | "quickinbox.com": true, 1055 | "quickmail.nl": true, 1056 | "r8.porco.cf": true, 1057 | "radiku.ye.vc": true, 1058 | "rajeshcon.cf": true, 1059 | "rcpt.at": true, 1060 | "re-gister.com": true, 1061 | "reality-concept.club": true, 1062 | "reallymymail.com": true, 1063 | "receiveee.chickenkiller.com": true, 1064 | "receiveee.com": true, 1065 | "recode.me": true, 1066 | "reconmail.com": true, 1067 | "recursor.net": true, 1068 | "recyclemail.dk": true, 1069 | "reddit.usa.cc": true, 1070 | "regbypass.com": true, 1071 | "regbypass.comsafe-mail.net": true, 1072 | "regspaces.tk": true, 1073 | "rejectmail.com": true, 1074 | "remail.cf": true, 1075 | "remail.ga": true, 1076 | "renault-clio.cf": true, 1077 | "resgedvgfed.tk": true, 1078 | "retkesbusz.nut.cc": true, 1079 | "rhyta.com": true, 1080 | "rk9.chickenkiller.com": true, 1081 | "rklips.com": true, 1082 | "rkomo.com": true, 1083 | "rmqkr.net": true, 1084 | "rootfest.net": true, 1085 | "royal.net": true, 1086 | "rppkn.com": true, 1087 | "rtrtr.com": true, 1088 | "rudymail.ml": true, 1089 | "ruffrey.com": true, 1090 | "ruru.be": true, 1091 | "rx.dred.ru": true, 1092 | "rx.qc.to": true, 1093 | "s.bloq.ro": true, 1094 | "s.dextm.ro": true, 1095 | "s.proprietativalcea.ro": true, 1096 | "s.sa.igg.biz": true, 1097 | "s.spamserver.flu.cc": true, 1098 | "s.vdig.com": true, 1099 | "s00.orangotango.ga": true, 1100 | "s0ny.net": true, 1101 | "sa.igg.biz": true, 1102 | "safe-mail.net": true, 1103 | "safersignup.de": true, 1104 | "safetymail.info": true, 1105 | "safetypost.de": true, 1106 | "sandelf.de": true, 1107 | "savelife.ml": true, 1108 | "saynotospams.com": true, 1109 | "scatmail.com": true, 1110 | "schafmail.de": true, 1111 | "secure-mail.biz": true, 1112 | "secure-mail.cc": true, 1113 | "securehost.com.es": true, 1114 | "selfdestructingmail.com": true, 1115 | "selfdestructingmail.org": true, 1116 | "sendspamhere.com": true, 1117 | "servermaps.net": true, 1118 | "sfmail.top": true, 1119 | "sharedmailbox.org": true, 1120 | "sharklasers.com": true, 1121 | "shieldedmail.com": true, 1122 | "shiftmail.com": true, 1123 | "shitaway.cf": true, 1124 | "shitaway.cu.cc": true, 1125 | "shitaway.flu.cc": true, 1126 | "shitaway.ga": true, 1127 | "shitaway.gq": true, 1128 | "shitaway.igg.biz": true, 1129 | "shitaway.ml": true, 1130 | "shitaway.nut.cc": true, 1131 | "shitaway.tk": true, 1132 | "shitaway.usa.cc": true, 1133 | "shitmail.de": true, 1134 | "shitmail.me": true, 1135 | "shitmail.org": true, 1136 | "shitware.nl": true, 1137 | "shockinmytown.cu.cc": true, 1138 | "shortmail.net": true, 1139 | "shotmail.ru": true, 1140 | "showslow.de": true, 1141 | "shuffle.email": true, 1142 | "siliwangi.ga": true, 1143 | "sinnlos-mail.de": true, 1144 | "siteposter.net": true, 1145 | "skeefmail.com": true, 1146 | "skrx.tk": true, 1147 | "sky-mail.ga": true, 1148 | "slaskpost.se": true, 1149 | "slave-auctions.net": true, 1150 | "slippery.email": true, 1151 | "slipry.net": true, 1152 | "slopsbox.com": true, 1153 | "slushmail.com": true, 1154 | "smap.4nmv.ru": true, 1155 | "smashmail.de": true, 1156 | "smellfear.com": true, 1157 | "smellrear.com": true, 1158 | "snakemail.com": true, 1159 | "sneakemail.com": true, 1160 | "snkmail.com": true, 1161 | "social-mailer.tk": true, 1162 | "sofimail.com": true, 1163 | "sofort-mail.de": true, 1164 | "softpls.asia": true, 1165 | "sogetthis.com": true, 1166 | "sohu.com": true, 1167 | "soisz.com": true, 1168 | "solar-impact.pro": true, 1169 | "solvemail.info": true, 1170 | "soodomail.com": true, 1171 | "soodonims.com": true, 1172 | "spam-a.porco.cf": true, 1173 | "spam-b.porco.cf": true, 1174 | "spam-be-gone.com": true, 1175 | "spam.2012-2016.ru": true, 1176 | "spam.flu.cc": true, 1177 | "spam.igg.biz": true, 1178 | "spam.la": true, 1179 | "spam.nut.cc": true, 1180 | "spam.orangotango.ml": true, 1181 | "spam.su": true, 1182 | "spam.usa.cc": true, 1183 | "spam4.me": true, 1184 | "spamavert.com": true, 1185 | "spambob.com": true, 1186 | "spambob.net": true, 1187 | "spambob.org": true, 1188 | "spambog.com": true, 1189 | "spambog.de": true, 1190 | "spambog.net": true, 1191 | "spambog.ru": true, 1192 | "spambooger.com": true, 1193 | "spambox.info": true, 1194 | "spambox.irishspringrealty.com": true, 1195 | "spambox.us": true, 1196 | "spamcannon.com": true, 1197 | "spamcannon.net": true, 1198 | "spamcero.com": true, 1199 | "spamcon.org": true, 1200 | "spamcorptastic.com": true, 1201 | "spamcowboy.com": true, 1202 | "spamcowboy.net": true, 1203 | "spamcowboy.org": true, 1204 | "spamday.com": true, 1205 | "spamdecoy.net": true, 1206 | "spamex.com": true, 1207 | "spamfighter.cf": true, 1208 | "spamfighter.ga": true, 1209 | "spamfighter.gq": true, 1210 | "spamfighter.ml": true, 1211 | "spamfighter.tk": true, 1212 | "spamfree.eu": true, 1213 | "spamfree24.com": true, 1214 | "spamfree24.de": true, 1215 | "spamfree24.eu": true, 1216 | "spamfree24.info": true, 1217 | "spamfree24.net": true, 1218 | "spamfree24.org": true, 1219 | "spamgoes.in": true, 1220 | "spamgourmet.com": true, 1221 | "spamgourmet.net": true, 1222 | "spamgourmet.org": true, 1223 | "spamherelots.com": true, 1224 | "spamhereplease.com": true, 1225 | "spamhole.com": true, 1226 | "spamify.com": true, 1227 | "spaminator.de": true, 1228 | "spamkill.info": true, 1229 | "spaml.com": true, 1230 | "spaml.de": true, 1231 | "spammotel.com": true, 1232 | "spamobox.com": true, 1233 | "spamoff.de": true, 1234 | "spamsalad.in": true, 1235 | "spamserver.cf": true, 1236 | "spamserver.flu.cc": true, 1237 | "spamserver.ml": true, 1238 | "spamserver.tk": true, 1239 | "spamslicer.com": true, 1240 | "spamspot.com": true, 1241 | "spamstack.net": true, 1242 | "spamthis.co.uk": true, 1243 | "spamthisplease.com": true, 1244 | "spamtrail.com": true, 1245 | "spamtroll.net": true, 1246 | "speed.1s.fr": true, 1247 | "sperma.cf": true, 1248 | "spikio.com": true, 1249 | "spoofmail.de": true, 1250 | "spybox.de": true, 1251 | "squizzy.de": true, 1252 | "squizzy.net": true, 1253 | "sr.ro.lt": true, 1254 | "sraka.xyz": true, 1255 | "sroff.com": true, 1256 | "ss.undo.it": true, 1257 | "ssoia.com": true, 1258 | "startkeys.com": true, 1259 | "stexsy.com": true, 1260 | "stinkefinger.net": true, 1261 | "stop-my-spam.cf": true, 1262 | "stop-my-spam.com": true, 1263 | "stop-my-spam.ga": true, 1264 | "stop-my-spam.ml": true, 1265 | "stop-my-spam.pp.ua": true, 1266 | "stop-my-spam.tk": true, 1267 | "streetwisemail.com": true, 1268 | "stromox.com": true, 1269 | "stuffmail.de": true, 1270 | "sudolife.me": true, 1271 | "sudolife.net": true, 1272 | "sudomail.biz": true, 1273 | "sudomail.com": true, 1274 | "sudomail.net": true, 1275 | "sudoverse.com": true, 1276 | "sudoverse.net": true, 1277 | "sudoweb.net": true, 1278 | "sudoworld.com": true, 1279 | "sudoworld.net": true, 1280 | "supergreatmail.com": true, 1281 | "supermailer.jp": true, 1282 | "superrito.com": true, 1283 | "superstachel.de": true, 1284 | "suremail.info": true, 1285 | "susi.ml": true, 1286 | "svk.jp": true, 1287 | "sweetxxx.de": true, 1288 | "szerz.com": true, 1289 | "t.psh.me": true, 1290 | "tafmail.com": true, 1291 | "taglead.com": true, 1292 | "tagyourself.com": true, 1293 | "talkinator.com": true, 1294 | "tapchicuoihoi.com": true, 1295 | "tarzan.usa.cc": true, 1296 | "tarzanmail.cf": true, 1297 | "tarzanmail.ml": true, 1298 | "teamspeak3.ga": true, 1299 | "teewars.org": true, 1300 | "teleosaurs.xyz": true, 1301 | "teleworm.com": true, 1302 | "teleworm.us": true, 1303 | "temp-mail.com": true, 1304 | "temp-mail.de": true, 1305 | "temp-mail.org": true, 1306 | "temp.bartdevos.be": true, 1307 | "temp.emeraldwebmail.com": true, 1308 | "temp.headstrong.de": true, 1309 | "temp.mail.y59.jp": true, 1310 | "tempail.com": true, 1311 | "tempalias.com": true, 1312 | "tempe-mail.com": true, 1313 | "tempemail.biz": true, 1314 | "tempemail.co.za": true, 1315 | "tempemail.com": true, 1316 | "tempemail.net": true, 1317 | "tempinbox.co.uk": true, 1318 | "tempinbox.com": true, 1319 | "tempmail.co": true, 1320 | "tempmail.it": true, 1321 | "tempmail.pro": true, 1322 | "tempmail.us": true, 1323 | "tempmail2.com": true, 1324 | "tempmaildemo.com": true, 1325 | "tempmailer.com": true, 1326 | "tempomail.fr": true, 1327 | "temporarily.de": true, 1328 | "temporarioemail.com.br": true, 1329 | "temporaryemail.net": true, 1330 | "temporaryemail.us": true, 1331 | "temporaryforwarding.com": true, 1332 | "temporaryinbox.com": true, 1333 | "tempsky.com": true, 1334 | "tempthe.net": true, 1335 | "tempymail.com": true, 1336 | "thanksnospam.info": true, 1337 | "thankyou2010.com": true, 1338 | "thecloudindex.com": true, 1339 | "thereddoors.online": true, 1340 | "thisisnotmyrealemail.com": true, 1341 | "thraml.com": true, 1342 | "thrma.com": true, 1343 | "throam.com": true, 1344 | "thrott.com": true, 1345 | "throwam.com": true, 1346 | "throwawayemailaddress.com": true, 1347 | "throwawaymail.com": true, 1348 | "throya.com": true, 1349 | "tilien.com": true, 1350 | "tittbit.in": true, 1351 | "tm.tosunkaya.com": true, 1352 | "tmail.ws": true, 1353 | "tmailinator.com": true, 1354 | "toiea.com": true, 1355 | "toomail.biz": true, 1356 | "top9appz.info": true, 1357 | "tradermail.info": true, 1358 | "tralalajos.ga": true, 1359 | "tralalajos.gq": true, 1360 | "tralalajos.ml": true, 1361 | "tralalajos.tk": true, 1362 | "trash-amil.com": true, 1363 | "trash-mail.at": true, 1364 | "trash-mail.cf": true, 1365 | "trash-mail.com": true, 1366 | "trash-mail.de": true, 1367 | "trash-mail.ga": true, 1368 | "trash-mail.gq": true, 1369 | "trash-mail.ml": true, 1370 | "trash-mail.tk": true, 1371 | "trash-me.com": true, 1372 | "trash2009.com": true, 1373 | "trash2010.com": true, 1374 | "trash2011.com": true, 1375 | "trashcanmail.com": true, 1376 | "trashdevil.com": true, 1377 | "trashdevil.de": true, 1378 | "trashemail.de": true, 1379 | "trashmail.at": true, 1380 | "trashmail.com": true, 1381 | "trashmail.de": true, 1382 | "trashmail.me": true, 1383 | "trashmail.net": true, 1384 | "trashmail.org": true, 1385 | "trashmail.ws": true, 1386 | "trashmailer.com": true, 1387 | "trashymail.com": true, 1388 | "trashymail.net": true, 1389 | "trayna.com": true, 1390 | "trbvm.com": true, 1391 | "trbvn.com": true, 1392 | "trbvo.com": true, 1393 | "trickmail.net": true, 1394 | "trillianpro.com": true, 1395 | "trump.flu.cc": true, 1396 | "trump.igg.biz": true, 1397 | "tryalert.com": true, 1398 | "turoid.com": true, 1399 | "turual.com": true, 1400 | "tvchd.com": true, 1401 | "tverya.com": true, 1402 | "twinmail.de": true, 1403 | "twoweirdtricks.com": true, 1404 | "ty.ceed.se": true, 1405 | "tyldd.com": true, 1406 | "u.0u.ro": true, 1407 | "u.10x.es": true, 1408 | "u.2sea.org": true, 1409 | "u.900k.es": true, 1410 | "u.civvic.ro": true, 1411 | "u.dmarc.ro": true, 1412 | "u.labo.ch": true, 1413 | "u14269.ml": true, 1414 | "uacro.com": true, 1415 | "ubismail.net": true, 1416 | "ucupdong.ml": true, 1417 | "uggsrock.com": true, 1418 | "uk.flu.cc": true, 1419 | "uk.igg.biz": true, 1420 | "uk.nut.cc": true, 1421 | "umail.net": true, 1422 | "unmail.ru": true, 1423 | "upliftnow.com": true, 1424 | "uplipht.com": true, 1425 | "urfey.com": true, 1426 | "uroid.com": true, 1427 | "used-product.fr": true, 1428 | "username.e4ward.com": true, 1429 | "ux.dob.jp": true, 1430 | "ux.uk.to": true, 1431 | "v.0v.ro": true, 1432 | "v.jsonp.ro": true, 1433 | "vaasfc4.tk": true, 1434 | "valemail.net": true, 1435 | "venompen.com": true, 1436 | "veryrealemail.com": true, 1437 | "vfemail.net": true, 1438 | "vickaentb.tk": true, 1439 | "vidchart.com": true, 1440 | "viditag.com": true, 1441 | "viewcastmedia.com": true, 1442 | "viewcastmedia.net": true, 1443 | "viewcastmedia.org": true, 1444 | "viroleni.cu.cc": true, 1445 | "visa.coms.hk": true, 1446 | "vkcode.ru": true, 1447 | "vomoto.com": true, 1448 | "vp.ycare.de": true, 1449 | "vps30.com": true, 1450 | "vssms.com": true, 1451 | "vubby.com": true, 1452 | "vw-golf.gq": true, 1453 | "vzlom4ik.tk": true, 1454 | "w.0w.ro": true, 1455 | "walala.org": true, 1456 | "walkmail.net": true, 1457 | "walkmail.ru": true, 1458 | "wasd.dropmail.me": true, 1459 | "wazabi.club": true, 1460 | "we.qq.my": true, 1461 | "web-contact.info": true, 1462 | "web-emailbox.eu": true, 1463 | "web-ideal.fr": true, 1464 | "web-mail.pp.ua": true, 1465 | "web.discard-email.cf": true, 1466 | "webcontact-france.eu": true, 1467 | "webemail.me": true, 1468 | "webm4il.info": true, 1469 | "webuser.in": true, 1470 | "wee.my": true, 1471 | "wefjo.grn.cc": true, 1472 | "weg-werf-email.de": true, 1473 | "wegwerf-email-addressen.de": true, 1474 | "wegwerf-emails.de": true, 1475 | "wegwerfadresse.de": true, 1476 | "wegwerfemail.de": true, 1477 | "wegwerfmail.de": true, 1478 | "wegwerfmail.info": true, 1479 | "wegwerfmail.net": true, 1480 | "wegwerfmail.org": true, 1481 | "wegwerpmailadres.nl": true, 1482 | "wetrainbayarea.com": true, 1483 | "wetrainbayarea.org": true, 1484 | "wfgdfhj.tk": true, 1485 | "wh4f.org": true, 1486 | "whatiaas.com": true, 1487 | "whatpaas.com": true, 1488 | "whatsaas.com": true, 1489 | "whopy.com": true, 1490 | "whtjddn.33mail.com": true, 1491 | "whyspam.me": true, 1492 | "wickmail.net": true, 1493 | "wilemail.com": true, 1494 | "willselfdestruct.com": true, 1495 | "winemaven.info": true, 1496 | "wiz2.site": true, 1497 | "wmail.cf": true, 1498 | "wollan.info": true, 1499 | "worldspace.link": true, 1500 | "wovz.cu.cc": true, 1501 | "wr.moeri.org": true, 1502 | "wronghead.com": true, 1503 | "wt2.orangotango.cf": true, 1504 | "wuzup.net": true, 1505 | "wuzupmail.net": true, 1506 | "www.bccto.me": true, 1507 | "www.e4ward.com": true, 1508 | "www.gishpuppy.com": true, 1509 | "www.mailinator.com": true, 1510 | "wwwnew.eu": true, 1511 | "xagloo.com": true, 1512 | "xemaps.com": true, 1513 | "xents.com": true, 1514 | "xing886.uu.gl": true, 1515 | "xmaily.com": true, 1516 | "xoxox.cc": true, 1517 | "xoxy.net": true, 1518 | "xww.ro": true, 1519 | "xy9ce.tk": true, 1520 | "xyzfree.net": true, 1521 | "xzsok.com": true, 1522 | "yandere.cu.cc": true, 1523 | "yapped.net": true, 1524 | "yeah.net": true, 1525 | "yellow.flu.cc": true, 1526 | "yellow.hotakama.tk": true, 1527 | "yellow.igg.biz": true, 1528 | "yep.it": true, 1529 | "yert.ye.vc": true, 1530 | "yogamaven.com": true, 1531 | "yomail.info": true, 1532 | "yopmail.com": true, 1533 | "yopmail.fr": true, 1534 | "yopmail.gq": true, 1535 | "yopmail.net": true, 1536 | "yopmail.pp.ua": true, 1537 | "yordanmail.cf": true, 1538 | "you-spam.com": true, 1539 | "youmail.ga": true, 1540 | "yourlifesucks.cu.cc": true, 1541 | "ypmail.webarnak.fr.eu.org": true, 1542 | "yroid.com": true, 1543 | "yuurok.com": true, 1544 | "z1p.biz": true, 1545 | "za.com": true, 1546 | "zain.site": true, 1547 | "zainmax.net": true, 1548 | "zaktouni.fr": true, 1549 | "ze.gally.jp": true, 1550 | "zehnminutenmail.de": true, 1551 | "zeta-telecom.com": true, 1552 | "zetmail.com": true, 1553 | "zhcne.com": true, 1554 | "zhouemail.510520.org": true, 1555 | "zippymail.info": true, 1556 | "zoaxe.com": true, 1557 | "zoemail.com": true, 1558 | "zoemail.net": true, 1559 | "zoemail.org": true, 1560 | "zombo.flu.cc": true, 1561 | "zombo.igg.biz": true, 1562 | "zombo.nut.cc": true, 1563 | "zomg.info": true, 1564 | "zxcv.com": true, 1565 | "zxcvbnm.com": true, 1566 | "zzz.com": true, 1567 | } 1568 | -------------------------------------------------------------------------------- /mailckd/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM alpine 3 | ENV MAILCKD_HOST=0.0.0.0 MAILCKD_PORT=80 4 | COPY mailckd / 5 | ENTRYPOINT ["/mailckd"] 6 | EXPOSE 80 7 | -------------------------------------------------------------------------------- /mailckd/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/caarlos0/env" 6 | "os" 7 | ) 8 | 9 | func DefaultConfig() Config { 10 | return Config{ 11 | Host: "localhost", 12 | Port: "6788", 13 | LogLevel: "info", 14 | FromEmail: "noreply@mailck.io", 15 | } 16 | } 17 | 18 | type Config struct { 19 | Host string `env:"MAILCKD_HOST"` 20 | Port string `env:"MAILCKD_PORT"` 21 | LogLevel string `env:"MAILCKD_LOG_LEVEL"` 22 | TextLogging bool `env:"MAILCKD_TEXT_LOGGING"` 23 | FromEmail string `env:"MAILCKD_FROM_EMAIL"` 24 | } 25 | 26 | func (c Config) HostPort() string { 27 | return c.Host + ":" + c.Port 28 | } 29 | 30 | func ReadConfig() *Config { 31 | c, err := readConfig(flag.NewFlagSet(os.Args[0], flag.ExitOnError), os.Args[1:]) 32 | if err != nil { 33 | // should never happen, because of flag default policy ExitOnError 34 | panic(err) 35 | } 36 | return c 37 | } 38 | 39 | func readConfig(f *flag.FlagSet, args []string) (*Config, error) { 40 | config := DefaultConfig() 41 | 42 | // Environment variables 43 | err := env.Parse(&config) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | f.StringVar(&config.Host, "host", config.Host, "The host to listen on") 49 | f.StringVar(&config.Port, "port", config.Port, "The port to listen on") 50 | f.StringVar(&config.LogLevel, "log-level", config.LogLevel, "The log level") 51 | f.BoolVar(&config.TextLogging, "text-logging", config.TextLogging, "Log in text format instead of json") 52 | f.StringVar(&config.FromEmail, "from-email", config.FromEmail, "The from email when connecting to the mailserver") 53 | 54 | // Arguments variables 55 | err = f.Parse(args) 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | return &config, err 61 | } 62 | -------------------------------------------------------------------------------- /mailckd/config_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/stretchr/testify/assert" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestConfig_ReadConfigDefaults(t *testing.T) { 11 | originalArgs := os.Args 12 | os.Args = []string{"mailckd"} 13 | defer func() { os.Args = originalArgs }() 14 | 15 | d := DefaultConfig() 16 | assert.Equal(t, &d, ReadConfig()) 17 | } 18 | 19 | func TestConfig_ReadConfig(t *testing.T) { 20 | input := []string{ 21 | "--host=host", 22 | "--port=port", 23 | "--log-level=loglevel", 24 | "--text-logging=true", 25 | "--from-email=foo@example.com", 26 | } 27 | 28 | expected := &Config{ 29 | Host: "host", 30 | Port: "port", 31 | LogLevel: "loglevel", 32 | TextLogging: true, 33 | FromEmail: "foo@example.com", 34 | } 35 | 36 | cfg, err := readConfig(flag.NewFlagSet("", flag.ContinueOnError), input) 37 | assert.NoError(t, err) 38 | assert.Equal(t, expected, cfg) 39 | } 40 | 41 | func TestConfig_ReadConfigFromEnv(t *testing.T) { 42 | assert.NoError(t, os.Setenv("MAILCKD_HOST", "host")) 43 | defer os.Unsetenv("MAILCKD_HOST") 44 | assert.NoError(t, os.Setenv("MAILCKD_PORT", "port")) 45 | defer os.Unsetenv("MAILCKD_PORT") 46 | assert.NoError(t, os.Setenv("MAILCKD_LOG_LEVEL", "loglevel")) 47 | defer os.Unsetenv("MAILCKD_LOG_LEVEL") 48 | assert.NoError(t, os.Setenv("MAILCKD_TEXT_LOGGING", "true")) 49 | defer os.Unsetenv("MAILCKD_TEXT_LOGGING") 50 | assert.NoError(t, os.Setenv("MAILCKD_FROM_EMAIL", "foo@example.com")) 51 | defer os.Unsetenv("MAILCKD_FROM_EMAIL") 52 | 53 | expected := &Config{ 54 | Host: "host", 55 | Port: "port", 56 | LogLevel: "loglevel", 57 | TextLogging: true, 58 | FromEmail: "foo@example.com", 59 | } 60 | 61 | cfg, err := readConfig(flag.NewFlagSet("", flag.ContinueOnError), []string{}) 62 | assert.NoError(t, err) 63 | assert.Equal(t, expected, cfg) 64 | } 65 | -------------------------------------------------------------------------------- /mailckd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/smancke/mailck" 5 | "github.com/tarent/lib-compose/logging" 6 | "net/http" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | ) 11 | 12 | const applicationName = "mailckd" 13 | 14 | func main() { 15 | config := ReadConfig() 16 | if err := logging.Set(config.LogLevel, config.TextLogging); err != nil { 17 | exit(nil, err) 18 | return // return here for unittesing 19 | } 20 | 21 | logShutdownEvent() 22 | 23 | logging.LifecycleStart(applicationName, config) 24 | 25 | checkFunc := func(checkEmail string) (result mailck.Result, err error) { 26 | return mailck.Check(config.FromEmail, checkEmail) 27 | } 28 | handlerChain := logging.NewLogMiddleware(NewValidationHandler(checkFunc)) 29 | 30 | exit(nil, http.ListenAndServe(config.HostPort(), handlerChain)) 31 | } 32 | 33 | func logShutdownEvent() { 34 | go func() { 35 | c := make(chan os.Signal) 36 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 37 | exit(<-c, nil) 38 | }() 39 | } 40 | 41 | func exit(signal os.Signal, err error) { 42 | logging.LifecycleStop(applicationName, signal, err) 43 | exitCode := 0 44 | if err != nil { 45 | exitCode = 1 46 | } 47 | osExit(exitCode) 48 | } 49 | 50 | var osExit = func(exitCode int) { 51 | os.Exit(exitCode) 52 | } 53 | -------------------------------------------------------------------------------- /mailckd/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/stretchr/testify/assert" 6 | "io/ioutil" 7 | "net/http" 8 | "os" 9 | "strings" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | func Test_ExitOnWrongLoglevel(t *testing.T) { 15 | exitCode := -1 16 | osExitOriginal := osExit 17 | defer func() { osExit = osExitOriginal }() 18 | osExit = func(code int) { 19 | exitCode = code 20 | } 21 | originalArgs := os.Args 22 | os.Args = []string{"mailckd", "-log-level=FOOO"} 23 | defer func() { os.Args = originalArgs }() 24 | 25 | main() 26 | assert.Equal(t, 1, exitCode) 27 | } 28 | 29 | func Test_BasicEndToEnd(t *testing.T) { 30 | originalArgs := os.Args 31 | os.Args = []string{"mailckd", "-host=localhost", "-port=3002", "-text-logging=false"} 32 | defer func() { os.Args = originalArgs }() 33 | 34 | go main() 35 | 36 | time.Sleep(time.Second) 37 | 38 | r, err := http.Post("http://localhost:3002/api/verify", "application/x-www-form-urlencoded", strings.NewReader(`mail=foo@example.com`)) 39 | assert.NoError(t, err) 40 | 41 | assert.Equal(t, 200, r.StatusCode) 42 | assert.Equal(t, "application/json", r.Header.Get("Content-Type")) 43 | 44 | b, err := ioutil.ReadAll(r.Body) 45 | assert.NoError(t, err) 46 | 47 | result := map[string]interface{}{} 48 | err = json.Unmarshal(b, &result) 49 | assert.NoError(t, err) 50 | 51 | assert.Equal(t, "invalid", result["result"]) 52 | assert.Equal(t, "invalidDomain", result["resultDetail"]) 53 | assert.Equal(t, "The email domain does not exist.", result["message"]) 54 | 55 | // test for 404 56 | r, err = http.Post("http://localhost:3002/api/foobar", "application/x-www-form-urlencoded", strings.NewReader(`mail=foo@example.com`)) 57 | assert.NoError(t, err) 58 | assert.Equal(t, 404, r.StatusCode) 59 | } 60 | -------------------------------------------------------------------------------- /mailckd/validation_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "github.com/smancke/mailck" 8 | "github.com/tarent/lib-compose/logging" 9 | "io/ioutil" 10 | "net/http" 11 | "strings" 12 | ) 13 | 14 | type parameters struct { 15 | Mail string `json:"mail"` 16 | Timeout string `json:"timeout"` 17 | } 18 | 19 | // MailValidationFunction checks the checkEmail 20 | type MailValidationFunction func(checkEmail string) (result mailck.Result, err error) 21 | 22 | // ValidationHandler is a REST handler for mail validation. 23 | type ValidationHandler struct { 24 | checkFunc MailValidationFunction 25 | } 26 | 27 | func NewValidationHandler(checkFunc MailValidationFunction) *ValidationHandler { 28 | return &ValidationHandler{ 29 | checkFunc: checkFunc, 30 | } 31 | } 32 | 33 | func (h *ValidationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 34 | w.Header().Set("Content-Type", "application/json") 35 | 36 | if r.Method != "GET" && r.Method != "POST" { 37 | writeError(w, 405, "clientError", "method not allowed") 38 | return 39 | } 40 | 41 | if r.Method == "POST" && 42 | !(r.Header.Get("Content-Type") == "application/json" || 43 | r.Header.Get("Content-Type") == "application/x-www-form-urlencoded") { 44 | writeError(w, 415, "clientError", "Unsupported Media Type") 45 | return 46 | } 47 | 48 | if !strings.HasSuffix(r.URL.Path, "/verify") { 49 | writeError(w, 404, "clientError", "ressource not found") 50 | return 51 | } 52 | 53 | p, err := h.readParameters(r) 54 | if err != nil { 55 | writeError(w, 400, "clientError", err.Error()) 56 | return 57 | } 58 | 59 | result, err := h.checkFunc(p.Mail) 60 | 61 | if err != nil { 62 | logging.Application(r.Header).WithError(err).WithField("mail", p.Mail).Info("check error") 63 | if result == mailck.MailserverError { 64 | w.WriteHeader(502) 65 | } else { 66 | w.WriteHeader(500) 67 | } 68 | } 69 | b, _ := json.MarshalIndent(result, "", " ") 70 | w.Write(b) 71 | } 72 | 73 | func (h *ValidationHandler) readParameters(r *http.Request) (parameters, error) { 74 | p := parameters{} 75 | 76 | if r.Header.Get("Content-Type") == "application/json" { 77 | body, _ := ioutil.ReadAll(r.Body) 78 | err := json.Unmarshal(body, &p) 79 | if err != nil { 80 | return p, err 81 | } 82 | } 83 | 84 | // overwrite by form paramters, if any 85 | r.ParseForm() 86 | if r.Form.Get("mail") != "" { 87 | p.Mail = r.Form.Get("mail") 88 | } 89 | if r.Form.Get("timeout") != "" { 90 | p.Timeout = r.Form.Get("timeout") 91 | } 92 | 93 | if p.Mail == "" { 94 | return p, errors.New("missing parameter: mail") 95 | } 96 | 97 | return p, nil 98 | } 99 | 100 | func writeError(w http.ResponseWriter, code int, resultDetail, message string) { 101 | w.WriteHeader(code) 102 | fmt.Fprintf(w, `{"result": "error", "resultDetail": "%v", "message": "%v"}`, resultDetail, message) 103 | } 104 | -------------------------------------------------------------------------------- /mailckd/validation_handler_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "github.com/smancke/mailck" 7 | "github.com/stretchr/testify/assert" 8 | "net/http" 9 | "net/http/httptest" 10 | "strings" 11 | "testing" 12 | ) 13 | 14 | func testValidationFunction(result mailck.Result, err error) MailValidationFunction { 15 | return func(checkEmail string) (mailck.Result, error) { 16 | if checkEmail != "foo@example.com" { 17 | panic("wrong email: " + checkEmail) 18 | } 19 | return result, err 20 | } 21 | } 22 | 23 | func Test_Requests(t *testing.T) { 24 | tests := []struct { 25 | title string 26 | validationFunction MailValidationFunction 27 | method string 28 | requestType string 29 | url string 30 | body string 31 | responseCode int 32 | responseType string 33 | result string 34 | resultDetail string 35 | message string 36 | }{ 37 | { 38 | title: "valid POST example", 39 | validationFunction: testValidationFunction(mailck.Valid, nil), 40 | method: "POST", 41 | requestType: "application/x-www-form-urlencoded", 42 | body: "mail=foo@example.com", 43 | responseCode: 200, 44 | result: "valid", 45 | resultDetail: "mailboxChecked", 46 | message: mailck.Valid.Message, 47 | }, 48 | { 49 | title: "valid JSON POST example", 50 | validationFunction: testValidationFunction(mailck.Valid, nil), 51 | method: "POST", 52 | requestType: "application/json", 53 | body: `{"mail": "foo@example.com"}`, 54 | responseCode: 200, 55 | result: "valid", 56 | resultDetail: "mailboxChecked", 57 | message: mailck.Valid.Message, 58 | }, 59 | { 60 | title: "valid GET example", 61 | url: "/verify?mail=foo%40example.com", 62 | validationFunction: testValidationFunction(mailck.Valid, nil), 63 | method: "GET", 64 | responseCode: 200, 65 | result: "valid", 66 | resultDetail: "mailboxChecked", 67 | message: mailck.Valid.Message, 68 | }, 69 | 70 | // error cases 71 | { 72 | title: "missing parameter", 73 | validationFunction: testValidationFunction(mailck.Valid, nil), 74 | method: "POST", 75 | requestType: "application/x-www-form-urlencoded", 76 | url: "/verify", 77 | body: "", 78 | responseCode: 400, 79 | result: "error", 80 | resultDetail: "clientError", 81 | message: "missing parameter: mail", 82 | }, 83 | { 84 | title: "JSON parsing error", 85 | validationFunction: testValidationFunction(mailck.Valid, nil), 86 | method: "POST", 87 | requestType: "application/json", 88 | body: `{"mail": "foo@example.com`, 89 | responseCode: 400, 90 | result: "error", 91 | resultDetail: "clientError", 92 | message: "unexpected end of JSON input", 93 | }, 94 | { 95 | title: "method not allowed", 96 | validationFunction: testValidationFunction(mailck.Valid, nil), 97 | method: "PUT", 98 | requestType: "application/json", 99 | body: `{"mail": "foo@example.com"}`, 100 | responseCode: 405, 101 | result: "error", 102 | resultDetail: "clientError", 103 | message: "method not allowed", 104 | }, 105 | { 106 | title: "wrong content type", 107 | validationFunction: testValidationFunction(mailck.Valid, nil), 108 | method: "POST", 109 | requestType: "text/plain", 110 | body: `{"mail": "foo@example.com"}`, 111 | responseCode: 415, 112 | result: "error", 113 | resultDetail: "clientError", 114 | message: "Unsupported Media Type", 115 | }, 116 | { 117 | title: "service error", 118 | validationFunction: testValidationFunction(mailck.ServiceError, errors.New("some error")), 119 | url: "/verify?mail=foo%40example.com", 120 | method: "GET", 121 | responseCode: 500, 122 | result: "error", 123 | resultDetail: "serviceError", 124 | message: mailck.ServiceError.Message, 125 | }, 126 | { 127 | title: "mailserver error", 128 | validationFunction: testValidationFunction(mailck.MailserverError, errors.New("some error")), 129 | url: "/verify?mail=foo%40example.com", 130 | method: "GET", 131 | responseCode: 502, 132 | result: "error", 133 | resultDetail: "mailserverError", 134 | message: mailck.MailserverError.Message, 135 | }, 136 | } 137 | 138 | for _, test := range tests { 139 | t.Run(test.title, func(t *testing.T) { 140 | handler := NewValidationHandler(test.validationFunction) 141 | url := "/verify" 142 | if test.url != "" { 143 | url = test.url 144 | } 145 | req, err := http.NewRequest(test.method, url, strings.NewReader(test.body)) 146 | if test.requestType != "" { 147 | req.Header.Set("Content-Type", test.requestType) 148 | } 149 | assert.NoError(t, err) 150 | resp := httptest.NewRecorder() 151 | 152 | handler.ServeHTTP(resp, req) 153 | 154 | assert.Equal(t, test.responseCode, resp.Code) 155 | assert.Equal(t, "application/json", resp.Header().Get("Content-Type")) 156 | 157 | result := getJson(t, resp) 158 | assert.Equal(t, test.result, result["result"]) 159 | assert.Equal(t, test.resultDetail, result["resultDetail"]) 160 | assert.Equal(t, test.message, result["message"]) 161 | }) 162 | } 163 | } 164 | 165 | func getJson(t *testing.T, resp *httptest.ResponseRecorder) map[string]interface{} { 166 | result := map[string]interface{}{} 167 | err := json.Unmarshal(resp.Body.Bytes(), &result) 168 | assert.NoError(t, err) 169 | return result 170 | } 171 | -------------------------------------------------------------------------------- /result.go: -------------------------------------------------------------------------------- 1 | package mailck 2 | 3 | type ResultState string 4 | 5 | const ( 6 | ValidState ResultState = "valid" 7 | InvalidState = "invalid" 8 | ErrorState = "error" 9 | ) 10 | 11 | func (rs ResultState) String() string { 12 | return string(rs) 13 | } 14 | 15 | // Result contains the information about an email check. 16 | type Result struct { 17 | Result ResultState `json:"result"` 18 | ResultDetail string `json:"resultDetail"` 19 | Message string `json:"message"` 20 | } 21 | 22 | var ( 23 | Valid = Result{ValidState, "mailboxChecked", "The email address is valid."} 24 | InvalidSyntax = Result{InvalidState, "invalidSyntax", "The email format is invalid."} 25 | InvalidDomain = Result{InvalidState, "invalidDomain", "The email domain does not exist."} 26 | MailboxUnavailable = Result{InvalidState, "mailboxUnavailable", "The email username does not exist."} 27 | Disposable = Result{InvalidState, "disposable", "The email is a throw-away address."} 28 | MailserverError = Result{ErrorState, "mailserverError", "The target mailserver responded with an error."} 29 | TimeoutError = Result{ErrorState, "timeoutError", "The connection with the mailserver timed out."} 30 | NetworkError = Result{ErrorState, "networkError", "The connection to the mailserver could not be made."} 31 | ServiceError = Result{ErrorState, "serviceError", "An internal error occured while checking."} 32 | ClientError = Result{ErrorState, "clientError", "The request was was invalid."} 33 | ) 34 | 35 | func (r Result) IsValid() bool { 36 | return r.Result == ValidState 37 | } 38 | 39 | func (r Result) IsInvalid() bool { 40 | return r.Result == InvalidState 41 | } 42 | 43 | func (r Result) IsError() bool { 44 | return r.Result == ErrorState 45 | } 46 | --------------------------------------------------------------------------------