addr

package
v0.0.0-...-2b86a76 Latest Latest
Warning

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

Go to latest
Published: Jan 5, 2022 License: MIT Imports: 8 Imported by: 3

Documentation

Overview

Package addr is the primary entry point for working with email addresses.

Roundtripping

Generally speaking, roundtripping is not desireable when it comes to email addresses. If you are parsing an old email to harvest the email addresses from it, you want to make sure any new email being created to those email addresses use the current format rather than any obsolete format that may have been in use. Use the String() or CleanString() methods to get the canonical string for use with new messages and documents.

However, there are caes where being able to understand the details of the address and still be able to output the original is still what is wanted. This library is capable of helping you to a limited extent in preserving the original strings. Use the OriginalString() methods to retrieve the original string for roundtripping.

There is a caveat though...

The Mailbox, AddrSpec, and Group objects all store the originally parsed text when they are created by the parser. However, the lists of email addresses (either AddressList or MailboxList) are not quite able to totally preserve the original as these are just slices. Any extra comments or whitespace not associated with a mailbox or group email address in the originally parsed text will be lost by those data structures.

Example

A basic example on how the package works.

package main

import (
	"fmt"

	"github.com/zostay/go-addr/pkg/addr"
)

func main() {
	addresses := "\"J.R.R. Tolkein\" <j.r.r.tolkein@example.com>, \"C.S. Lewis\" <jack@example.com>"
	as, err := addr.ParseEmailAddressList(addresses)
	if err != nil {
		panic(err)
	}

	for _, a := range as {
		fmt.Println("Name: " + a.DisplayName())
		fmt.Println("Addr: " + a.Address())
	}

}
Output:

Name: J.R.R. Tolkein
Addr: j.r.r.tolkein@example.com
Name: C.S. Lewis
Addr: jack@example.com
Example (MailboxListRoundtripping)

This example shows how the original is lost when parsing a mailbox list. The same will happen with an address list. Both the clean and original are the same in this case. Oddities within email addresses will be preserved, but other bits will not be.

package main

import (
	"fmt"

	"github.com/zostay/go-addr/pkg/addr"
)

func main() {
	addresses := ", (weird stuff), \"J.R.R. Tolkein\" <j.r.r.tolkein@example.com>, \"C.S. Lewis\" <jack@example.com>, (wacky)"
	mbs, _ := addr.ParseEmailMailboxList(addresses)
	fmt.Println(mbs)
	fmt.Println(mbs.OriginalString())
}
Output:

"J.R.R. Tolkein" <j.r.r.tolkein@example.com>, "C.S. Lewis" <jack@example.com>
"J.R.R. Tolkein" <j.r.r.tolkein@example.com>, "C.S. Lewis" <jack@example.com>
Example (MailboxRoundtripping)

Here is an example showing the difference between clean strings and original strings for full roundtripping on a Mailbox. ParseEmailAddress, ParseEmailAddrSpec, and ParseEmailGroup will work similarly.

package main

import (
	"fmt"

	"github.com/zostay/go-addr/pkg/addr"
)

func main() {
	mb, _ := addr.ParseEmailMailbox("\"Orson Scott Card\" <ender(weird comment placement)@example.com>")
	fmt.Println(mb)
	fmt.Println(mb.OriginalString())
}
Output:

"Orson Scott Card" <ender@example.com> (weird comment placement)
"Orson Scott Card" <ender(weird comment placement)@example.com>

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrParseConstruction indicates that the parser was able to match the
	// string, but that object does not produce any output for construction.
	// This error should never occur unless you make a direct call to
	// ApplyActions on a rd.Match tag for which ApplyActions does not produce an
	// object.
	ErrParseConstruction = errors.New("parse construction error")

	// ErrTypeMismatch indicates that the parser was able to match the string,
	// but the type of object produced by that match does not match the pointer
	// provided as the second argument to ApplyActions. The built-in Parse
	// functions will never do this.
	ErrTypeMismatch = errors.New("type mismatch")

	// ErrTypeUnknown indicates that the parser was able to match the string,
	// but then the ApplyActions routine produced an object that it has not been
	// written to handle. If this error occurs, there is a bug in the package.
	ErrTypeUnknown = errors.New("unknown applied type")

	// ErrParse indicates that the parser was unable to match the given input.
	ErrParse = errors.New("unable to parse email address")
)

This is the list of errors that may be returned while parsing and resolving the results of the parse.

View Source
var (
	// ErrCommentUnbalancedRight error is returned when constructing a mailbox
	// and the comment given contains too many right parentheses.
	ErrCommentUnbalancedRight = errors.New("comments must contain balanced parentheses; found too many ')'")

	// ErrCommentUnbalancedLeft error is returned when constructing a mailbox
	// and the comment given contains too many left parentheses.
	ErrCommentUnbalancedLeft = errors.New("comments must contain balanced parentheses; found too many '('")
)
View Source
var (
	// CharsetReader is used to help perform MIME word decoding.
	CharsetReader func(charset string, input io.Reader) (io.Reader, error)
)

Functions

func ApplyActions

func ApplyActions(m *rd.Match, mk interface{}) error

ApplyActions is a low-level function that can be used to transform an rd.Match object returned by the Parser into a high-level address object. This function is called internally by the Parse functions to produce objects from parsed strings.

The second argument must be a pointer to the object that the given rd.Match should produce (or it may be set to nil). This method will then evaluate the Match and all components of the Match to construct an object. If the resulting object is compatible with the pointer, it will be assigned or converted to the correct type and then assigned to it. (For example, if the parse produced an AddrSpec, but the second argument is a pointer to *Mailbox, the AddrSpec will be wrapped in a Mailbox first.)

If the second argument is nil, this method will still construct all the objects associated with the match and all components of the match. These can be retrieved by walking the tree and checking the m.Made part of each match.

On success, the second argument will be set to the constructed object (unless the second argument was nil) and the error will be returned as nil.

On failure, an error is returned and the second argument will not be set. The match tree may be fully or partially modified to set Made.

In any case, the tree itself will be unmodified except for assignment to the Made field of the match and other components.

Types

type AddrSpec

type AddrSpec struct {
	// contains filtered or unexported fields
}

AddrSpec is a concrete type for holding a single email address with no metadata. This is just the "local@domain" bit with no display name or comment information. It can also track the original string parsed to produce the object for the purpose of roundtripping.

func NewAddrSpec

func NewAddrSpec(localPart, domain string) *AddrSpec

NewAddrSpec creates a new AddrSpec object from the given local part and domain.

func NewAddrSpecParsed

func NewAddrSpecParsed(lp, d, o string) *AddrSpec

NewAddrSpecParsed creates a new AddrSpec object from the given local part and domain and stores an originally parsed string for roundtripping.

func ParseEmailAddrSpec

func ParseEmailAddrSpec(a string) (*AddrSpec, error)

ParseEmailAddrSpec parses the given email string for a bare email.

On success it will return either the email address. If the email address successfully parses, but there is text remaining after the address, a PartialParseError will be returned as well.

On failure, the object will be nil and an error will be returned.

func (*AddrSpec) Address

func (as *AddrSpec) Address() string

Address is an alias for CleanString.

func (*AddrSpec) CleanString

func (as *AddrSpec) CleanString() string

CleanString will return a clean version of the email address suitable for use in new email messages.

func (*AddrSpec) Comment

func (as *AddrSpec) Comment() string

Comment always returns an empty string.

func (*AddrSpec) DisplayName

func (as *AddrSpec) DisplayName() string

DisplayName always returns an empty string.

func (*AddrSpec) Domain

func (as *AddrSpec) Domain() string

Domain returns the part of the email address after the at sign.

func (*AddrSpec) LocalPart

func (as *AddrSpec) LocalPart() string

LocalPart returns the part of the email address from before the at sign.

func (*AddrSpec) OriginalString

func (as *AddrSpec) OriginalString() string

OriginalString returns the originally parsed string if that string is set. This is useful for roundtripping. However, if you are building a new email, it is best to use the CleanString. See https://tools.ietf.org/html/rfc5322#section-4

func (*AddrSpec) SetDomain

func (as *AddrSpec) SetDomain(d string)

SetDomain sets the part of the email address after the at sign. This will also clear the original string if set.

func (*AddrSpec) SetLocalPart

func (as *AddrSpec) SetLocalPart(lp string)

SetLocalPart sets the part of the email address before the at sign. This will also clear the original string if set.

func (*AddrSpec) String

func (as *AddrSpec) String() string

String is an alias for CleanString.

type Address

type Address interface {
	DisplayName() string    // name associated with the group
	Address() string        // mailbox address(es) as a string
	OriginalString() string // the originally parsed string for round-tripping
	CleanString() string    // a clean string if you want the canonical email string
	Comment() string        // the comment associated with this address
}

Address represents a generic email address. This could be either a mailbox address or a group address.

func ParseEmailAddress

func ParseEmailAddress(a string) (Address, error)

ParseEmailAddress will parse any single email address. This could actually be multiple mailbox addresses if the email address is a group address. The object returned will either be a *Group or a *Mailbox.

An error is returned if there's a problem during the parse. If the parse is partially successful, the address will be returned and a PartialParseError object will be returned.

type AddressList

type AddressList []Address

AddressList is a slice of Address objects.

func ParseEmailAddressList

func ParseEmailAddressList(a string) (AddressList, error)

ParseEmailAddressList will parse any list of addresses. Individual addresses may either be mailboxes or groups.

func (AddressList) CleanString

func (as AddressList) CleanString() string

CleanString returns the canonical version of the addresses in the list joined together with a comma and a space.

func (AddressList) Flatten

func (as AddressList) Flatten() MailboxList

Flatten returns the AddressList as a MailboxList. This returns a slice of Mailboxes. If the AddressList contains any groups, then the returned MailboxList will contain all the mailboxes within those groups.

func (AddressList) OriginalString

func (as AddressList) OriginalString() string

OriginalString is not entirely a reproduction of the original. An AddressList is just a slice of Address, which means it does not preserve the original in any way. The addresses will be identical to the parsed original, though. It will join these with a comma followed by a space.

Any address in the list that was not parsed or has no original string will actually be the canonical string instead.

func (AddressList) String

func (as AddressList) String() string

String is an alias for CleanString.

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group is the concrete object for holding a named group of email addresses.

func NewGroupParsed

func NewGroupParsed(dn string, l MailboxList, o string) *Group

NewGroupParsed constructs and returns a group email address with an associated original string.

func ParseEmailGroup

func ParseEmailGroup(a string) (*Group, error)

ParseEmailGroup parses the string as a group email address and returns the group found.

This may return a group with no error, a group with an error, or just an error depending on the input.

If the entire string is parsed and understood to be a group email address, it will return the group and no error.

If the first part of the string is parsed and found to be a group email address, it will return what it could parse and also a PartialParseError.

If their is an error parsing the string and no part of a group is found, this will return no group object and an error.

func (*Group) Address

func (g *Group) Address() string

Address returns the CleanString for the MailboxList.

func (*Group) CleanString

func (g *Group) CleanString() string

CleanString returns the canonical version of the group email address string.

func (*Group) Comment

func (g *Group) Comment() string

Comment always returns the empty string.

func (*Group) DisplayName

func (g *Group) DisplayName() string

DisplayName returns the display name of the group of email addresses.

func (*Group) MailboxList

func (g *Group) MailboxList() MailboxList

MailboxList returns the slice of mailbox address for this group.

func (*Group) OriginalString

func (g *Group) OriginalString() string

OriginalString will return the originally parsed string, if that string is set. This is useful for roundtripping.

func (*Group) SetDisplayName

func (g *Group) SetDisplayName(dn string)

SetDisplayName updates the display name. It will also clear the original string if one is set.

func (*Group) SetMailboxList

func (g *Group) SetMailboxList(mbs MailboxList)

SetMailboxList updates the slice of the mailbox address for this group. It will also clear the original string if one is set.

func (*Group) String

func (g *Group) String() string

String is an alias for CleanString.

type Mailbox

type Mailbox struct {
	// contains filtered or unexported fields
}

Mailbox is a concrete type for storing a mailbox email address.

Example (ConvertToMailAddress)

A quick demo on how to convert these mailboxes into addresses for use with net/mail.

package main

import (
	"fmt"
	"net/mail"

	"github.com/zostay/go-addr/pkg/addr"
)

func main() {
	addrmb, _ := addr.ParseEmailMailbox("\"David Weber\" <honorh@example.com>")
	mailmb := mail.Address{
		Name:    addrmb.DisplayName(),
		Address: addrmb.Address(),
	}
	fmt.Println(mailmb)
}
Output:

{David Weber honorh@example.com}

func NewMailbox

func NewMailbox(
	displayName string,
	addrSpec *AddrSpec,
	comment string,
) (*Mailbox, error)

NewMailbox will construct a new mailbox from the given display name, AddrSpec, and comment.

This will return ErrCommentUnbalancedRight or ErrCommentUnbalancedLeft if a comment is given that contains mismatched parentheses.

On success, returns the constructed mailbox object.

func NewMailboxParsed

func NewMailboxParsed(
	displayName string,
	addrSpec *AddrSpec,
	comment,
	original string,
) (*Mailbox, error)

NewMailboxParsed will construct a new mailbox from the given display name, AddrSpec, and comment, and will provide the given original as the originally parsed string. This is useful for allowing for the round-tripping of an email address.

This will return ErrCommentUnbalancedRight or ErrCommentUnbalancedLeft if a comment is given that contains mismatched parantheses.

On success, returns the constructed mailbox object.

func NewMailboxStr

func NewMailboxStr(dn string, as string, c string) (*Mailbox, error)

NewMailboxStr is identical in operation to NewMailbox except that it takes the addrSpec argument as a string. This will be parsed into an AddrSpec to be added to the object.

This will return the error from ParseEmailAddrSpec if the internal call to the parser fails.

If ParseEmailAddrSpec returns a PartialParseError, this method will fail with that PartialParseError and fail to construct the object.

This will return ErrCommentUnbalancedRight or ErrCommentUnbalancedLeft if a comment is given that contains mismatched parantheses.

On success, returns the constructed mailbox object.

func ParseEmailMailbox

func ParseEmailMailbox(a string) (*Mailbox, error)

ParseEmailMailbox parses the email mailbox string.

It is possible for this method to return a mailbox and an error, or just a mailbox with no error, or just an error.

If the parse succeeds and there's no remaining unparsed text, the mailbox object will be returned and error will be nil.

If the parse partially succeeds, the mailbox object will be constructed and returned and a PartialParseError is returned.

If the parse fails, the error is returned and mailbox is nil.

func (*Mailbox) AddrSpec

func (m *Mailbox) AddrSpec() *AddrSpec

AddrSpec returns the AddrSpec used to store the email address in detail.

func (*Mailbox) Address

func (m *Mailbox) Address() string

Address returns the address part of the email address as a string in angle brackets. This will return the clean address.

func (*Mailbox) CleanString

func (m *Mailbox) CleanString() string

CleanString returns a proper RFC 5322 email address. If the originally parsed email address was using an obsolete format, this will return the correct version according to spec.

func (*Mailbox) Comment

func (m *Mailbox) Comment() string

Comment returns the accumulated comment for the email address as a string or it returns an empty string if there is no comment.

func (*Mailbox) DisplayName

func (m *Mailbox) DisplayName() string

DisplayName returns the display name of the email address or an empty string.

func (*Mailbox) Domain

func (m *Mailbox) Domain() string

Domain is syntactic sugar for

m.AddrSpec().Domain()

func (*Mailbox) GuessName

func (m *Mailbox) GuessName() string

GuessName is a helper function aimed at helping you guess what name should be associated with the user. The logic works like this:

1. If a display name is present, it will return the display name.

2. If a comment is present, it will return the comment.

3. Fallback to the local part of the email address.

Returns the guessed string.

func (*Mailbox) LocalPart

func (m *Mailbox) LocalPart() string

LocalPart is syntactic sugar for

m.AddrSpec().LocalPart()

func (*Mailbox) OriginalString

func (m *Mailbox) OriginalString() string

OriginalString either returns the originally parsed string used to create this mailbox or an empty string. This is useful for roundtripping, but it should not be used for generating new email. See https://tools.ietf.org/html/rfc5322#section-4

func (*Mailbox) SetAddrSpec

func (m *Mailbox) SetAddrSpec(as *AddrSpec)

SetAddrSpec will update the email address for the mailbox. This will also clear the original string if one is set.

func (*Mailbox) SetAddress

func (m *Mailbox) SetAddress(a string) error

SetAddress will change the email address stored. It parses the string using ParseAddrSpec and updates the object. This will clear the original string if one is set.

This will return the error from ParseEmailAddrSpec if the internal call to the parser fails.

If ParseEmailAddrSpec returns a PartialParseError, the address will not be set.

On success, returns nil.

func (*Mailbox) SetComment

func (m *Mailbox) SetComment(c string)

SetComment will update the comment for the mailbox. This will also clear the original string if one is set.

func (*Mailbox) SetDisplayName

func (m *Mailbox) SetDisplayName(dn string)

SetDisplayName will update the display name for the mailbox. This will also clear an original string if one is set.

func (*Mailbox) String

func (m *Mailbox) String() string

String is an alias for CleanString.

type MailboxList

type MailboxList []*Mailbox

MailboxList is a slice of mailbox pointers.

func ParseEmailMailboxList

func ParseEmailMailboxList(a string) (MailboxList, error)

ParseEmailMailboxList parses a list of mailbox email addresses. Group addresses are not permitted in this parse.

It is possible for this method to return a list of mailboxes and an error, or just a list of mailboxes with no error, or just an error.

If the parse success and there's no remaining unparsed text, the mailbox list is returned and the error will be nil.

If the parse partially succeeds, the mailbox list will be returned as well as a PartialParseError.

If the parse fails, teh error is returned and the returned slice will be nil.

func (MailboxList) AddressList

func (ms MailboxList) AddressList() AddressList

AddressList will transform a MailboxList into an AddressList with the same mailboxes.

func (MailboxList) CleanString

func (ms MailboxList) CleanString() string

CleanString returns the email addresses in the canonical RFC 5322 format separated by a comma.

func (MailboxList) OriginalString

func (ms MailboxList) OriginalString() string

OriginalString returns all the email addresses using their original format for round-tripping.

Please note, though, that this slice does not store the complete mailbox list original, so this will not round-trip the originally parsed content. Any superfluous whitespace or comments not directly associated with a mailbox address will be lost.

func (MailboxList) String

func (ms MailboxList) String() string

String is an alias for CleanString.

type PartialParseError

type PartialParseError struct {
	Remainder string // This is the remaining unparsed string.
}

PartialParseError is returned when one of the Parse functions is able to parse a value out from the start of the string, but was unable to match the entire string. This might mean that the string contains additional text after the piece it is able to parse or it might mean that the input is formatted okay at the start, but contains some unparseable garbage in the middle or end. This error allows your implementation to decide whether or not a partial parse is acceptable or not.

Example

This example shows how you can recover from a partial parse, if you want.

package main

import (
	"errors"
	"fmt"

	"github.com/zostay/go-addr/pkg/addr"
)

func main() {
	mb, err := addr.ParseEmailMailbox(
		"\"CS\" <charles.sheffield@example.com> and extra text",
	)

	var r string
	var ppe addr.PartialParseError
	if errors.As(err, &ppe) {
		r = ppe.Remainder
	} else if err != nil {
		panic(err)
	}

	fmt.Printf("Parsed: %s\n", mb)
	fmt.Printf("Remainder: %s\n", r)

}
Output:

Parsed: CS <charles.sheffield@example.com>
Remainder: and extra text

func (PartialParseError) Error

func (PartialParseError) Error() string

Error returns the message "incomplete parsing of email address".

Directories

Path Synopsis
Package encoding defines a custom CharsetReader for expanding the encodings that are available for the MIME word decoders used when parsing email addresses.
Package encoding defines a custom CharsetReader for expanding the encodings that are available for the MIME word decoders used when parsing email addresses.

Jump to

Keyboard shortcuts

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