mail

package module
v0.0.0-...-94f5967 Latest Latest
Warning

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

Go to latest
Published: Mar 19, 2022 License: MIT, PostgreSQL Imports: 12 Imported by: 0

README

go-mail

Important note: go-mail is EXPERIMENTAL. It parses many messages correctly, but may return incorrect results or even crash with certain inputs. Many code paths lack test coverage. The API surface may change. You’ve been warned! :)

Build Status

go-mail is a robust RFC5322/2822/822 message parser.

Motivation

Email parsing is a pain. It spans many RFCs (e.g. 5322, 2045, 2046, 2047, 4289, 2049, 4288, 4021, 6532) and includes joys like:

  • Comment-folding white space
  • 7-bit encoding
  • Content transfer encodings
    • quoted printable
    • base64
  • Encoded words (=?utf-8?q?email=20is=20hard?=)
  • Multipart messages

… and that’s when things going smoothly. In practice, malformed messages are commonplace. go-mail accepts this reality and makes a best effort to interpret each message based on the sender’s intent.

Installation

go get github.com/paulrosania/go-mail

Documentation

Full API documentation is available here:

https://godoc.org/github.com/paulrosania/go-mail

Contributing

  1. Fork the project
  2. Make your changes
  3. Run tests (go test)
  4. Send a pull request!

If you’re making a big change, please open an issue first, so we can discuss.

Thanks

  • Archiveopteryx, for providing a liberally-licensed, robust C++ parser. Much of the original go-mail implementation was derived from it.
  • Roger Peppe, for the original go-charset library. (go-mail uses a fork.)

License

go-mail is provided under the MIT license. Major portions of the original implementation were derived from the excellent Archiveopteryx RFC2822 parser, which is provided under the PostgreSQL license. See the LICENSE file for details.

Documentation

Index

Constants

View Source
const (
	FromFieldName                    = "From"
	ResentFromFieldName              = "Resent-From"
	SenderFieldName                  = "Sender"
	ResentSenderFieldName            = "Resent-Sender"
	ReturnPathFieldName              = "Return-Path"
	ReplyToFieldName                 = "Reply-To"
	ToFieldName                      = "To"
	CcFieldName                      = "Cc"
	BccFieldName                     = "Bcc"
	ResentToFieldName                = "Resent-To"
	ResentCcFieldName                = "Resent-Cc"
	ResentBccFieldName               = "Resent-Bcc"
	MessageIDFieldName               = "Message-ID"
	ResentMessageIDFieldName         = "Resent-Message-ID"
	InReplyToFieldName               = "In-Reply-To"
	ReferencesFieldName              = "References"
	DateFieldName                    = "Date"
	OrigDateFieldName                = "Orig-Date"
	ResentDateFieldName              = "Resent-Date"
	SubjectFieldName                 = "Subject"
	CommentsFieldName                = "Comments"
	KeywordsFieldName                = "Keywords"
	ContentTypeFieldName             = "Content-Type"
	ContentTransferEncodingFieldName = "Content-Transfer-Encoding"
	ContentDispositionFieldName      = "Content-Disposition"
	ContentDescriptionFieldName      = "Content-Description"
	ContentIDFieldName               = "Content-ID"
	MIMEVersionFieldName             = "MIME-Version"
	ReceivedFieldName                = "Received"
	ContentLanguageFieldName         = "Content-Language"
	ContentLocationFieldName         = "Content-Location"
	ContentMd5FieldName              = "Content-Md5"
	ListIdFieldName                  = "List-Id"
	ContentBaseFieldName             = "Content-Base"
	ErrorsToFieldName                = "Errors-To"
)
View Source
const (
	RFC5322Header headerMode = iota
	MIMEHeader
)
View Source
const (
	TextPlainContentType defaultContentType = iota // default
	MessageRFC822ContentType
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Address

type Address struct {
	Localpart string
	Domain    string
	// contains filtered or unexported fields
}

func NewAddress

func NewAddress(name, localpart, domain string) Address

func (*Address) Name

func (a *Address) Name(avoidUTF8 bool) string

Returns the name stored in this Address. The name is the RFC 2822 display-part, or in case of memberless groups, the display-name of the group.

A memberless group is stored as an Address whose localpart() and domain() are both empty.

func (*Address) String

func (a *Address) String() string

type AddressField

type AddressField struct {
	HeaderField
	Addresses Addresses
}

func NewAddressField

func NewAddressField(name string) *AddressField

func (*AddressField) Parse

func (f *AddressField) Parse(s string)

func (*AddressField) Value

func (f *AddressField) Value() string

type AddressParser

type AddressParser struct {
	Addresses Addresses
	// contains filtered or unexported fields
}

The AddressParser class helps parse email addresses and lists.

In the interests of simplicity, AddressParser parses everything as if it were a list of addresses - either of the mailbox-list or address-list productions in RFC 2822. The user of this class must check that the supplied addresses fit the (often more specific) requirements.

AddressParser supports most of RFC 822 and 2822, but mostly omits address groups. An empty address group is translated into a single Address, a nonempty group is translated into the equivalent number of addresses.

AddressParser does not attempt to canonicalize the addresses parsed or get rid of duplicates (To: ams@oryx.com, ams@ory.com), it only parses.

The first error seen is stored and can be accessed using error().

func NewAddressParser

func NewAddressParser(s string) AddressParser

Constructs an Address Parser parsing \a s. After construction, addresses() and error() may be accessed immediately.

type AddressType

type AddressType int
const (
	NormalAddressType AddressType = iota
	BounceAddressType
	EmptyGroupAddressType
	LocalAddressType
	InvalidAddressType
)

type Addresses

type Addresses []Address

func (*Addresses) Uniquify

func (as *Addresses) Uniquify()

Removes any addresses that exist twice in the list.

type BoringType

type BoringType int
const (
	TotallyBoring BoringType = iota
	IMAPBoring
	MIMEBoring
)

type ContentDisposition

type ContentDisposition struct {
	MIMEField
	Disposition string
}

func NewContentDisposition

func NewContentDisposition() *ContentDisposition

func (*ContentDisposition) Parse

func (f *ContentDisposition) Parse(s string)

type ContentLanguage

type ContentLanguage struct {
	MIMEField
	Languages []string
}

func NewContentLanguage

func NewContentLanguage() *ContentLanguage

func (*ContentLanguage) Parse

func (f *ContentLanguage) Parse(s string)

type ContentTransferEncoding

type ContentTransferEncoding struct {
	MIMEField
	Encoding EncodingType
}

func NewContentTransferEncoding

func NewContentTransferEncoding() *ContentTransferEncoding

func (*ContentTransferEncoding) Parse

func (f *ContentTransferEncoding) Parse(s string)

type ContentType

type ContentType struct {
	MIMEField
	Type, Subtype string
}

func NewContentType

func NewContentType() *ContentType

func (*ContentType) Parse

func (f *ContentType) Parse(s string)

type DateField

type DateField struct {
	HeaderField
	Date *time.Time
}

func NewDateField

func NewDateField() *DateField

func (*DateField) Parse

func (f *DateField) Parse(s string)

TODO: Evaluate aox implementation, might be more lenient

type EncodedTextType

type EncodedTextType int
const (
	EncodedText EncodedTextType = iota
	EncodedComment
	EncodedPhrase
)

type EncodingType

type EncodingType int
const (
	QPEncoding EncodingType = iota
	Base64Encoding
	UuencodeEncoding
	BinaryEncoding
)

type Field

type Field interface {
	Name() string
	Value() string
	Error() error

	Parse(value string)
	Valid() bool
	UnparsedValue() string
	SetUnparsedValue(value string)
	// contains filtered or unexported methods
}

func NewHeaderField

func NewHeaderField(name, value string) Field

func NewHeaderFieldNamed

func NewHeaderFieldNamed(name string) Field
type Header struct {
	Fields []Field
	// contains filtered or unexported fields
}

func ReadHeader

func ReadHeader(rfc5322 string, m headerMode) (h *Header, err error)

func (*Header) Add

func (h *Header) Add(key, value string)

Add adds the key, value pair to the header. It appends to any existing values associated with the key.

func (*Header) Addresses

func (h *Header) Addresses(fn string) []Address

Returns a pointer to the addresses in the \a t header field, which must be an address field such as From or Bcc. If not, or if the field is empty, addresses() returns a null pointer.

func (*Header) AsText

func (h *Header) AsText(avoidUTF8 bool) string

Returns the canonical text representation of this Header. Downgrades rather than including UTF-8 if \a avoidUTF8 is true.

func (*Header) ContentDescription

func (h *Header) ContentDescription() string

Returns the value of the Content-Description field, or an empty string if there isn't one. RFC 2047 encoding is not considered - should it be?

func (*Header) ContentDisposition

func (h *Header) ContentDisposition() *ContentDisposition

Returns a pointer to the Content-Disposition header field, or a null pointer if there isn't one.

func (*Header) ContentLanguage

func (h *Header) ContentLanguage() *ContentLanguage

Returns a pointer to the Content-Language header field, or a null pointer if there isn't one.

func (*Header) ContentLocation

func (h *Header) ContentLocation() string

Returns the value of the Content-Location field, or an empty string if there isn't one. The URI is not validated in any way.

func (*Header) ContentTransferEncoding

func (h *Header) ContentTransferEncoding() *ContentTransferEncoding

Returns a pointer to the Content-Transfer-Encoding header field, or a null pointer if there isn't one.

func (*Header) ContentType

func (h *Header) ContentType() *ContentType

Returns a pointer to the Content-Type header field, or a null pointer if there isn't one.

func (*Header) Date

func (h *Header) Date() *time.Time

Returns the header's data \a t, which is the normal date by default, but can also be orig-date or resent-date. If there is no such field or \a t is meaningless, date() returns a null pointer.

func (*Header) Get

func (h *Header) Get(key string) string

Get gets the first value associated with the given key. If there are no values associated with the key, Get returns "".

func (*Header) MarshalJSON

func (h *Header) MarshalJSON() ([]byte, error)

func (*Header) MessageID

func (h *Header) MessageID() string

Returns the value of the Message-ID field, or an empty string if there isn't one or if there are multiple (which is illegal).

func (*Header) Remove

func (h *Header) Remove(r Field)

func (*Header) RemoveAllNamed

func (h *Header) RemoveAllNamed(name string)

func (*Header) RemoveAt

func (h *Header) RemoveAt(i int)

func (*Header) Repair

func (h *Header) Repair()

Repairs problems that can be repaired without knowing the associated bodypart.

func (*Header) RepairWithBody

func (h *Header) RepairWithBody(p *Part, body string)

Repairs a few harmless and common problems, such as inserting two Date fields with the same value. Assumes that \a p is its companion body (whose text is in \a body), and may look at it to decide what/how to repair.

func (*Header) Simplify

func (h *Header) Simplify()

Removes any redundant header fields from this header, and simplifies the value of some.

For example, if 'sender' or 'reply-to' points to the same address as 'from', that field can be removed, and if 'from' contains the same address twice, one can be removed.

func (*Header) Subject

func (h *Header) Subject() string

Returns the value of the first Subject header field. If there is no such field, returns the empty string.

func (*Header) ToMap

func (h *Header) ToMap() map[string][]string

func (*Header) UnmarshalJSON

func (h *Header) UnmarshalJSON(data []byte) error

func (*Header) Valid

func (h *Header) Valid() bool

Returns true if this Header fills all the conditions laid out in RFC 2821 for validity, and false if not.

type HeaderField

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

func (*HeaderField) Error

func (f *HeaderField) Error() error

func (*HeaderField) Name

func (f *HeaderField) Name() string

func (*HeaderField) Parse

func (f *HeaderField) Parse(s string)

Every HeaderField subclass must define a parse() function that takes a string \a s from a message and sets the field value(). This default function handles fields that are not specially handled by subclasses using functions like parseText().

func (*HeaderField) SetUnparsedValue

func (f *HeaderField) SetUnparsedValue(value string)

func (*HeaderField) UnparsedValue

func (f *HeaderField) UnparsedValue() string

func (*HeaderField) Valid

func (f *HeaderField) Valid() bool

Returns true if this header field is valid (or unparsed, as is the case for all unknown fields), and false if an error was detected during parsing.

func (*HeaderField) Value

func (f *HeaderField) Value() string

type HeaderFieldCondition

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

type MIMEField

type MIMEField struct {
	HeaderField

	Parameters []MIMEParameter
	// contains filtered or unexported fields
}

func (*MIMEField) Value

func (f *MIMEField) Value() string

Like HeaderField::value(), returns the contents of this MIME field in a representation suitable for storage.

type MIMEParameter

type MIMEParameter struct {
	Name, Value string
	Parts       []string
}

func NewMIMEParameter

func NewMIMEParameter(name, value string) MIMEParameter

type Message

type Message struct {
	*Part
	RFC822Size   int `json:"size"`
	InternalDate int `json:"-"`
}

func NewMessage

func NewMessage() *Message

func ReadMessage

func ReadMessage(rfc5322 string) (*Message, error)

func (*Message) Body

func (m *Message) Body(avoidUTF8 bool) string

Returns the text representation of the body of this message.

func (*Message) BodyPart

func (m *Message) BodyPart(s string, create bool) *Part

Returns a pointer to the Bodypart whose IMAP part number is \a s and possibly create it. Creates Bodypart objects if \a create is true. Returns null pointer if \a s is not valid and \a create is false.

func (*Message) Parse

func (m *Message) Parse(rfc5322 string) error

func (*Message) RFC822

func (m *Message) RFC822(avoidUTF8 bool) string

Returns the message formatted in RFC 822 (actually 2822) format. The return value is a canonical expression of the message, not whatever was parsed.

If \a avoidUTF8 is true, this function loses information rather than including UTF-8 in the result.

type Part

type Part struct {
	Header *Header `json:"header"`
	Parts  []*Part `json:"parts,omitempty"`
	Number int     `json:"-"`

	Text string `json:"text,omitempty"`
	Data string `json:"data,omitempty"`
	// contains filtered or unexported fields
}

func (*Part) AsText

func (p *Part) AsText(avoidUTF8 bool) string

Returns the text representation of this Bodypart.

Notes: This function seems uncomfortable. It returns just one of many possible text representations, and the exact choice seems arbitrary, and finally, it does rather overlap with text() and data().

We probably should transition away from this function.

The exact representation returned uses base64 encoding for data types and no ContentTransferEncoding. For text types, it encodes the text according to the ContentType.

Jump to

Keyboard shortcuts

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