subaddressing support, closes #61
This commit is contained in:
2
vendor/github.com/mcnijman/go-emailaddress/.gitignore
generated
vendored
Normal file
2
vendor/github.com/mcnijman/go-emailaddress/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
emailaddress
|
||||
coverage.*
|
||||
25
vendor/github.com/mcnijman/go-emailaddress/.travis.yml
generated
vendored
Normal file
25
vendor/github.com/mcnijman/go-emailaddress/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go:
|
||||
- "1.11.x"
|
||||
- "1.10.x"
|
||||
- "1.9.x"
|
||||
- tip
|
||||
env:
|
||||
global:
|
||||
- GO111MODULE=on
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
||||
install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- GO111MODULE=off go get -u github.com/securego/gosec/cmd/gosec/...
|
||||
script:
|
||||
- go get -t -v ./...
|
||||
- diff -u <(echo -n) <(gofmt -d -s .)
|
||||
- go tool vet .
|
||||
- $GOPATH/bin/gosec ./...
|
||||
- go test -race -covermode=atomic -coverprofile=coverage.txt ./...
|
||||
- $GOPATH/bin/goveralls -coverprofile=coverage.txt -service=travis-ci
|
||||
21
vendor/github.com/mcnijman/go-emailaddress/LICENCE
generated
vendored
Normal file
21
vendor/github.com/mcnijman/go-emailaddress/LICENCE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Thijs Nijman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
102
vendor/github.com/mcnijman/go-emailaddress/README.md
generated
vendored
Normal file
102
vendor/github.com/mcnijman/go-emailaddress/README.md
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
# go-emailaddress #
|
||||
|
||||
[](https://godoc.org/github.com/mcnijman/go-emailaddress) [](https://travis-ci.org/mcnijman/go-emailaddress) [](https://coveralls.io/github/mcnijman/go-emailaddress?branch=master) [](https://goreportcard.com/report/github.com/mcnijman/go-emailaddress)
|
||||
|
||||
go-emailaddress is a tiny Go library for finding, parsing and validating email addresses. This
|
||||
library is tested for Go v1.9 and above.
|
||||
|
||||
Note that there is no such thing as perfect email address validation other than sending an actual
|
||||
email (ie. with a confirmation token). This library however checks if the email format conforms to
|
||||
the spec and if the host (domain) is actually able to receive emails. You can also use this library
|
||||
to find emails in a byte array. This package was created as similar packages don't seem to be
|
||||
maintained anymore (ie contain bugs with pull requests still open), and/or use wrong local
|
||||
validation.
|
||||
|
||||
## Usage ##
|
||||
|
||||
```bash
|
||||
go get -u github.com/mcnijman/go-emailaddress
|
||||
```
|
||||
|
||||
### Parsing and local validation ###
|
||||
|
||||
Parse and validate the email locally using RFC 5322 regex, note that when `err == nil` it doesn't
|
||||
necessarily mean the email address actually exists.
|
||||
|
||||
```go
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
email, err := emailaddress.Parse("foo@bar.com")
|
||||
if err != nil {
|
||||
fmt.Println("invalid email")
|
||||
}
|
||||
|
||||
fmt.Println(email.LocalPart) // foo
|
||||
fmt.Println(email.Domain) // bar.com
|
||||
fmt.Println(email) // foo@bar.com
|
||||
fmt.Println(email.String()) // foo@bar.com
|
||||
```
|
||||
|
||||
### Validating the host ###
|
||||
|
||||
Host validation will first attempt to resolve the domain and then verify if we can start a mail
|
||||
transaction with the host. This is relatively slow as it will contact the host several times.
|
||||
Note that when `err == nil` it doesn't necessarily mean the email address actually exists.
|
||||
|
||||
```go
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
email, err := emailaddress.Parse("foo@bar.com")
|
||||
if err != nil {
|
||||
fmt.Println("invalid email")
|
||||
}
|
||||
|
||||
err := email.ValidateHost()
|
||||
if err != nil {
|
||||
fmt.Println("invalid host")
|
||||
}
|
||||
```
|
||||
|
||||
### Finding emails ###
|
||||
|
||||
This will look for emails in a byte array (ie text or an html response).
|
||||
|
||||
```go
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
text := []byte(`Send me an email at foo@bar.com.`)
|
||||
validateHost := false
|
||||
|
||||
emails := emailaddress.Find(text, validateHost)
|
||||
|
||||
for _, e := range emails {
|
||||
fmt.Println(e)
|
||||
}
|
||||
// foo@bar.com
|
||||
```
|
||||
|
||||
As RFC 5322 is really broad this method will likely match images and urls that contain
|
||||
the '@' character (ie. !--logo@2x.png). For more reliable results, you can use the following method.
|
||||
|
||||
```go
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
text := []byte(`Send me an email at foo@bar.com or fake@domain.foobar.`)
|
||||
validateHost := false
|
||||
|
||||
emails := emailaddress.FindWithIcannSuffix(text, validateHost)
|
||||
|
||||
for _, e := range emails {
|
||||
fmt.Println(e)
|
||||
}
|
||||
// foo@bar.com
|
||||
```
|
||||
|
||||
## Versioning ##
|
||||
|
||||
This library uses [semantic versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## License ##
|
||||
|
||||
This library is distributed under the MIT license found in the [LICENSE](./LICENSE)
|
||||
file.
|
||||
224
vendor/github.com/mcnijman/go-emailaddress/emailaddress.go
generated
vendored
Normal file
224
vendor/github.com/mcnijman/go-emailaddress/emailaddress.go
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright 2018 The go-emailaddress AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package emailaddress provides a tiny library for finding, parsing and validation of email
|
||||
addresses. This library is tested for Go v1.9 and above.
|
||||
|
||||
go get -u github.com/mcnijman/go-emailaddress
|
||||
|
||||
Local validation
|
||||
|
||||
Parse and validate the email locally using RFC 5322 regex, note that when err == nil it doesn't
|
||||
necessarily mean the email address actually exists.
|
||||
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
email, err := emailaddress.Parse("foo@bar.com")
|
||||
if err != nil {
|
||||
fmt.Println("invalid email")
|
||||
}
|
||||
|
||||
fmt.Println(email.LocalPart) // foo
|
||||
fmt.Println(email.Domain) // bar.com
|
||||
fmt.Println(email) // foo@bar.com
|
||||
fmt.Println(email.String()) // foo@bar.com
|
||||
|
||||
Host validation
|
||||
|
||||
Host validation will first attempt to resolve the domain and then verify if we can start a mail
|
||||
transaction with the host. This is relatively slow as it will contact the host several times.
|
||||
Note that when err == nil it doesn't necessarily mean the email address actually exists.
|
||||
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
email, err := emailaddress.Parse("foo@bar.com")
|
||||
if err != nil {
|
||||
fmt.Println("invalid email")
|
||||
}
|
||||
|
||||
err := email.ValidateHost()
|
||||
if err != nil {
|
||||
fmt.Println("invalid host")
|
||||
}
|
||||
|
||||
Finding emails
|
||||
|
||||
This will look for emails in a byte array (ie text or an html response).
|
||||
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
text := []byte(`Send me an email at foo@bar.com.`)
|
||||
validateHost := false
|
||||
|
||||
emails := emailaddress.Find(text, validateHost)
|
||||
|
||||
for _, e := range emails {
|
||||
fmt.Println(e)
|
||||
}
|
||||
// foo@bar.com
|
||||
|
||||
As RFC 5322 is really broad this method will likely match images and urls that contain
|
||||
the '@' character (ie. !--logo@2x.png). For more reliable results, you can use the following method.
|
||||
|
||||
import "github.com/mcnijman/go-emailaddress"
|
||||
|
||||
text := []byte(`Send me an email at foo@bar.com or fake@domain.foobar.`)
|
||||
validateHost := false
|
||||
|
||||
emails := emailaddress.FindWithIcannSuffix(text, validateHost)
|
||||
|
||||
for _, e := range emails {
|
||||
fmt.Println(e)
|
||||
}
|
||||
// foo@bar.com
|
||||
|
||||
*/
|
||||
package emailaddress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
var (
|
||||
// rfc5322 is a RFC 5322 regex, as per: https://stackoverflow.com/a/201378/5405453.
|
||||
// Note that this can't verify that the address is an actual working email address.
|
||||
// Use ValidateHost as a starter and/or send them one :-).
|
||||
rfc5322 = "(?i)(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
|
||||
validEmailRegexp = regexp.MustCompile(fmt.Sprintf("^%s*$", rfc5322))
|
||||
findEmailRegexp = regexp.MustCompile(rfc5322)
|
||||
)
|
||||
|
||||
// EmailAddress is a structure that stores the address local-part@domain parts.
|
||||
type EmailAddress struct {
|
||||
// LocalPart usually the username of an email address.
|
||||
LocalPart string
|
||||
|
||||
// Domain is the part of the email address after the last @.
|
||||
// This should be DNS resolvable to an email server.
|
||||
Domain string
|
||||
}
|
||||
|
||||
func (e EmailAddress) String() string {
|
||||
if e.LocalPart == "" || e.Domain == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s@%s", e.LocalPart, e.Domain)
|
||||
}
|
||||
|
||||
// ValidateHost will test if the email address is actually reachable. It will first try to resolve
|
||||
// the host and then start a mail transaction.
|
||||
func (e EmailAddress) ValidateHost() error {
|
||||
host, err := lookupHost(e.Domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tryHost(host, e)
|
||||
}
|
||||
|
||||
// ValidateIcanSuffix will test if the public suffix of the domain is managed by ICANN using
|
||||
// the golang.org/x/net/publicsuffix package. If not it will return an error. Note that if this
|
||||
// method returns an error it does not necessarily mean that the email address is invalid. Also the
|
||||
// suffix list in the standard package is embedded and thereby not up to date.
|
||||
func (e EmailAddress) ValidateIcanSuffix() error {
|
||||
d := strings.ToLower(e.Domain)
|
||||
if s, icann := publicsuffix.PublicSuffix(d); !icann {
|
||||
return fmt.Errorf("public suffix is not managed by ICANN, got %s", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find uses the RFC 5322 regex to match, parse and validate any email addresses found in a string.
|
||||
// If the validateHost boolean is true it will call the validate host for every email address
|
||||
// encounterd. As RFC 5322 is really broad this method will likely match images and urls that
|
||||
// contain the '@' character.
|
||||
func Find(haystack []byte, validateHost bool) (emails []*EmailAddress) {
|
||||
results := findEmailRegexp.FindAll(haystack, -1)
|
||||
for _, r := range results {
|
||||
if e, err := Parse(string(r)); err == nil {
|
||||
if validateHost {
|
||||
if err := e.ValidateHost(); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
emails = append(emails, e)
|
||||
}
|
||||
}
|
||||
return emails
|
||||
}
|
||||
|
||||
// FindWithIcannSuffix uses the RFC 5322 regex to match, parse and validate any email addresses
|
||||
// found in a string. It will return emails if its eTLD is managed by the ICANN organization.
|
||||
// If the validateHost boolean is true it will call the validate host for every email address
|
||||
// encounterd. As RFC 5322 is really broad this method will likely match images and urls that
|
||||
// contain the '@' character.
|
||||
func FindWithIcannSuffix(haystack []byte, validateHost bool) (emails []*EmailAddress) {
|
||||
results := Find(haystack, false)
|
||||
for _, e := range results {
|
||||
if err := e.ValidateIcanSuffix(); err == nil {
|
||||
if validateHost {
|
||||
if err := e.ValidateHost(); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
emails = append(emails, e)
|
||||
}
|
||||
}
|
||||
return emails
|
||||
}
|
||||
|
||||
// Parse will parse the input and validate the email locally. If you want to validate the host of
|
||||
// this email address remotely call the ValidateHost method.
|
||||
func Parse(email string) (*EmailAddress, error) {
|
||||
if !validEmailRegexp.MatchString(email) {
|
||||
return nil, fmt.Errorf("format is incorrect for %s", email)
|
||||
}
|
||||
|
||||
i := strings.LastIndexByte(email, '@')
|
||||
e := &EmailAddress{
|
||||
LocalPart: email[:i],
|
||||
Domain: email[i+1:],
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// lookupHost first checks if any MX records are available and if not, it will check
|
||||
// if A records are available as they can resolve email server hosts. An error indicates
|
||||
// that non of the A or MX records are available.
|
||||
func lookupHost(domain string) (string, error) {
|
||||
if mx, err := net.LookupMX(domain); err == nil {
|
||||
return mx[0].Host, nil
|
||||
}
|
||||
if ips, err := net.LookupIP(domain); err == nil {
|
||||
return ips[0].String(), nil // randomly returns IPv4 or IPv6 (when available)
|
||||
}
|
||||
return "", fmt.Errorf("failed finding MX and A records for domain %s", domain)
|
||||
}
|
||||
|
||||
// tryHost will verify if we can start a mail transaction with the host.
|
||||
func tryHost(host string, e EmailAddress) error {
|
||||
client, err := smtp.Dial(fmt.Sprintf("%s:%d", host, 25))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if err = client.Hello(e.Domain); err == nil {
|
||||
if err = client.Mail(fmt.Sprintf("hello@%s", e.Domain)); err == nil {
|
||||
if err = client.Rcpt(e.String()); err == nil {
|
||||
client.Reset() // #nosec
|
||||
client.Quit() // #nosec
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user