emailsupport

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2024 License: MIT Imports: 3 Imported by: 0

README

emailsupport

This package contains auxiliary support information and routines for dealing with email handling.

Build Status Documentation Coverage Status

At present, it only has some regular expressions which have been tested by being in use for many years, in Perl, but have here been translated to Golang's regexp library. Other bits and pieces will creep in, as this package acts as a ‘miscellaneous’ catch-all for anything Golang that's email-related. As such, I'm not prepared to make API guarantees, so be sure to use dependency management to track this repository.

Using

This package follows normal Go package naming convention and is go get compatible.

The package is documented using the native godoc system. A public interface is available at godoc.org.

The allowed syntax for email addresses changes between RFC2821/RFC2822 and their replacements, RFC5321/RFC5322. By default, the regular expressions employ the newer syntax definitions, but you can build the library with a build-tag of rfc2822 to use the definitions supplied in RFC2822 instead of those from RFC5321.

This package uses semantic versioning.
Note that Go only supports the most recent two minor versions of the language; for the purposes of semver, we do not consider it a breaking change to add a dependency upon a language or standard library feature supported by all currently-supported releases of Go.

Tools

This is primarily a library package. It does include two commands though. This follows the standard Go idiom of using sub-directories of ./cmd to hold the commands. Thus you can use go install ./cmd/... to install them.

Or: go install -v github.com/philpennock/emailsupport/cmd/...@latest

  1. email-regexp-emit: just prints a regular expression for an email address. The pattern uses (?:  ) as a non-capturing group and is otherwise a simple Extended Regular Expression, so just about any modern regular expression library should be able to use it.

  2. check-is-emailaddr: can be given regexps on the command-line, or via an input file, and for each one reports success or failure. It exits true (0) if and only if every address given is fine. It exits 1 if some input is not an email address. It exists another non-zero value for problems in running.

Testing

Run go test

Documentation

Overview

Package emailsupport contains some more esoteric routines useful for parsing and handling email. For instance, some baroque regular expressions.

No APIs are stable. Make sure you handle your dependencies accordingly.

REGULAR EXPRESSIONS

The package creates a number of exported regular expression objects, initialised at init time, pulling up the creation cost to program start. Per the documentation for the `regexp` package, “A Regexp is safe for concurrent use by multiple goroutines.”

Each regular expression comes in two forms, `Foo` and `FooUnanchored`. The short name is anchored to the start and end of the pattern namespace, so that by default if you match an variable against `EmailAddress`, you are confirming that the contents of the variable are an email address, not accidentally only matching that there's something address-like somewhere within. The longer name (I need something briefer which is still clear) provides a pattern which can be used to find a regular expression elsewhere.

Each regular expression is available as a pattern string in a form with a `Txt` prefix, which can be used to build larger regular expressions. The pattern is wrapped with `(?:...)` to be a non-capturing group which can be qualified or otherwise treated as a single unit. No regular expression has any capturing groups, letting the caller manage capturing indices.

Thus for any `Foo`, this package provides:

  • TxtFoo: the regular expression as a text string, safe for embedding
  • Foo: a regexp object which is anchored to start and end
  • FooUnanchored: a regexp object which is not anchored

The list includes:

  • `EmailAddress`: an RFC5321 email address, the part within angle-brackets or as is used in SMTP. This is _not_ an RFC5322 message header email email address, with display forms and comments.

  • `EmailDomain`: a domain which can be used in email addresses; this is the base specification form and does not handle internationalisation, though this regexp should be correct to apply against punycode-encoded domains. This does handle embedded IPv4 and IPv6 address literals, but not the General-address-literal which is a grammar hook for future extension (because that inherently can't be handled until defined).

  • `EmailLHS`: the Left-Hand-Side (or "local part") of an email address; this handles unquoted and quoted forms.

  • `EmailAddressOrUnqualified`: either an address or a LHS, this is a form often used in mail configuration files where a domain is implicit.

  • `IPv4Address`, `IPv6Address`: an IPv4 or IPv6 address

  • `IPv4Netblock`, `IPv6Netblock`, IPNetblock: a netblock in CIDR prefix/len notation (used for source ACLs)

  • `IPv4Octet`: a number 0 to 255

The IPv6 address regexp is taken from RFC3986 (the one which gets it right) and is a careful copy/paste and edit of a version which has been used and gradually debugged for years, including in a tool I released called `emit_ipv6_regexp`.

The patterns used in `EmailLHS` (and thus also in items which include an email left-hand-side) can be in one of two forms, and selecting between them is a compile-time decision. The rules can be either those from RFC2822 or those from RFC5321. By default, those from RFC5321 are used. Build with a `rfc2822` build-tag to get the older definitions. If a future RFC changes the rules again, then the default patterns in this package may change; the build-tag `rfc5321` is currently unused, but is reserved for the future to force selecting the rules which are now current. It is safe (harmless) to supply that build-tag now (but not together with `rfc2822`).

Index

Constants

View Source
const (
	TxtIPv4Octet    = `(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])`
	TxtIPv4Address  = `(?:(?:` + TxtIPv4Octet + `\.){3}` + TxtIPv4Octet + `)`
	TxtIPv4Netblock = `(?:` + TxtIPv4Address + `/(?:[12]?[0-9]|3[0-2]))`
)

Variables

View Source
var (
	IPv4OctetUnanchored    = regexp.MustCompile(TxtIPv4Octet)
	IPv4Octet              = regexp.MustCompile(start + TxtIPv4Octet + end)
	IPv4AddressUnanchored  = regexp.MustCompile(TxtIPv4Address)
	IPv4Address            = regexp.MustCompile(start + TxtIPv4Address + end)
	IPv4NetblockUnanchored = regexp.MustCompile(TxtIPv4Netblock)
	IPv4Netblock           = regexp.MustCompile(start + TxtIPv4Netblock + end)
)
View Source
var (
	TxtIPv6Address = strings.Join([]string{`(?:`,
		`(?:(?:(?:`, txtIPv6H16, `:){6})`, txtIPv6LS32, `)|`,
		`(?:(?:::(?:`, txtIPv6H16, `:){5})`, txtIPv6LS32, `)|`,
		`(?:(?:(?:`, txtIPv6H16, `)?::(?:`, txtIPv6H16, `:){4})`, txtIPv6LS32, `)|`,
		`(?:(?:(?:(?:`, txtIPv6H16, `:){0,1}`, txtIPv6H16, `)?::(?:`, txtIPv6H16, `:){3})`, txtIPv6LS32, `)|`,
		`(?:(?:(?:(?:`, txtIPv6H16, `:){0,2}`, txtIPv6H16, `)?::(?:`, txtIPv6H16, `:){2})`, txtIPv6LS32, `)|`,
		`(?:(?:(?:(?:`, txtIPv6H16, `:){0,3}`, txtIPv6H16, `)?::`, txtIPv6H16, `:)`, txtIPv6LS32, `)|`,
		`(?:(?:(?:(?:`, txtIPv6H16, `:){0,4}`, txtIPv6H16, `)?::)`, txtIPv6LS32, `)|`,
		`(?:(?:(?:(?:`, txtIPv6H16, `:){0,5}`, txtIPv6H16, `)?::)`, txtIPv6H16, `)|`,
		`(?:(?:(?:(?:`, txtIPv6H16, `:){0,6}`, txtIPv6H16, `)?::))`,
		`)`}, "")
	TxtIPv6Netblock = `(?:` + TxtIPv6Address + `/(?:[1-9]?[0-9]|1[01][0-9]|12[0-8]))`
	TxtIPNetblock   = `(?:` + TxtIPv4Netblock + `|` + TxtIPv6Netblock + `)`
)
View Source
var (
	IPv6AddressUnanchored  = regexp.MustCompile(TxtIPv6Address)
	IPv6Address            = regexp.MustCompile(start + TxtIPv6Address + end)
	IPv6NetblockUnanchored = regexp.MustCompile(TxtIPv6Netblock)
	IPv6Netblock           = regexp.MustCompile(start + TxtIPv6Netblock + end)
	IPNetblockUnanchored   = regexp.MustCompile(TxtIPNetblock)
	IPNetblock             = regexp.MustCompile(start + TxtIPNetblock + end)
)
View Source
var (
	EmailLHSUnanchored                  = regexp.MustCompile(TxtEmailLHS)
	EmailLHS                            = regexp.MustCompile(start + TxtEmailLHS + end)
	EmailDomainUnanchored               = regexp.MustCompile(TxtEmailDomain)
	EmailDomain                         = regexp.MustCompile(start + TxtEmailDomain + end)
	EmailAddressUnanchored              = regexp.MustCompile(TxtEmailAddress)
	EmailAddress                        = regexp.MustCompile(start + TxtEmailAddress + end)
	EmailAddressOrUnqualifiedUnanchored = regexp.MustCompile(TxtEmailAddressOrUnqualified)
	EmailAddressOrUnqualified           = regexp.MustCompile(start + TxtEmailAddressOrUnqualified + end)
)
View Source
var TxtEmailAddress = `(?:(?:` + TxtEmailLHS + `)@(?:` + TxtEmailDomain + `))`
View Source
var TxtEmailAddressOrUnqualified = `(?:` + TxtEmailLHS + `(?:@` + TxtEmailDomain + `)?)`
View Source
var TxtEmailDomain string = deExtend(`
	 # Domain
	 (?:
		(?:
		 # regular domain
		 (?:[A-Za-z0-9] (?: [A-Za-z0-9-]*[A-Za-z0-9] )?)
		 (?: \. [A-Za-z0-9] (?: [A-Za-z0-9-]*[A-Za-z0-9] )?)+
		) | (?:
			 # address-literals
			 \[
			   (?: ` + TxtIPv4Address + ` | (?: [Ii][Pp][vV]6: ` + TxtIPv6Address + ` ) )
			   # NOTSUPP: General-address-literal
			   # G-A-L is a hook for future literal addresses
			   # and only specifies tag:content
			 \]
		)
	 )`)
View Source
var TxtEmailLHS string = deExtend(`
	 # Local-part
	 (?:
	  (?:
		# Dot-string
		(?:` + txtAText + `)+ (?: \. ` + txtAText + `+)*
	  ) | (?:
		# Quoted-string
		" (?: ` + txtWrapFWS + ` (?:
		 (?: ` + txtQText + `+ ) |
		 (?: \\ ` + txtQPairFollow + ` )
		) )* ` + txtWrapFWS + ` "
	  )
	 )`)

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL