mimestream

package module
v0.0.0-...-27c74eb Latest Latest
Warning

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

Go to latest
Published: May 24, 2019 License: MIT Imports: 18 Imported by: 0

README

mimestream

Performant, low-memory multipart/mime library for building and parsing email bodies in Go.

Status: Work In Progress

Writer Usage

Simple create a struct containing the parts as needed. Attach an io.Reader and file contents (or a network connection) will be streamed without requiring everything to be loaded into memory.

// Assuming this is some type of io.Reader or io.ReadCloser
var openfilehandle io.ReadCloser

parts := mimestream.Parts{
  mimestream.Alternative{
    Parts: []mimestream.Part{
      mimestream.Text{
        Text: "This is the text that goes in the plain part.",
      },
      mimestream.Text{
        ContentType: mimestream.TextHTML,
        Text:        "<p>This is the text that goes in the plain part.</p>",
      },
    },
  },
  mimestream.File{
    Name:   "filename.jpg",
    Inline: true,
    Reader: openfilehandle,
    Closer: openfilehandle,
  },
  mimestream.File{
    Name:   "payload.json",
    Reader: strings.NewReader(`{"one":1,"two":2}`),
  },
}

// Destination could be file or network connection, here we just throw it away
mr := multipart.NewWriter(ioutil.Discard)

err = parts.Into(mr)
if err != nil {
  log.Fatal(err)
}

Reader Usage

Reading emails is done with a simple callback that provides a place to stream each part to a destination. In the example below we simply read everything.

// Assume mailreader is a network connection or email file
var mailreader io.Reader

err = HandleEmailFromReader(mailreader, func(header textproto.MIMEHeader, body io.Reader) (err error) {
  maxbytes := 1024 * 1024

  var b []byte
  b, err = ioutil.ReadAll(io.LimitReader(body, maxbytes))
  if err != nil {
    return
  }

  fmt.Printf("Part Header: %v\n", header)
  fmt.Printf("Part body: %q\n", b)

  return
})

TODO

  • More Tests
  • Support writing nested parts
  • Multipart mixed and alternative

Why

Most multipart/mime handling by both email and MIME libraries in Go requires everything to be loaded into memory. I wanted to be able to create mime bodies without needing much memory.

Here are some of the following problems this package addresses:

  1. Requires memory equal to mime content (+ encoding)
  2. Uses string building to construct envelope (instead of using encoding/mime)

Similar libraries

Resources

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// Unformatted Text
	TextPlain = "text/plain; charset=utf-8"

	// HTML
	TextHTML = "text/html; charset=utf-8"

	// Markdown
	TextMarkdown = "text/markdown; charset=utf-8"

	// File attachments
	MultipartMixed = "multipart/mixed"

	// Text and HTML content
	MultipartAlternative = "multipart/alternative"
)

Content Types

View Source
var ErrMaximumMultipartDepth = errors.New("Mimestream: Maximum multipart/mime nesting level reached")
View Source
var ErrMaximumPartsPerMultipart = errors.New("Mimestream: Maximum number of multipart/mime parts reached")
View Source
var ErrMissingBoundary = errors.New("Missing boundary")

ErrMissingBoundary for multipart bodies without a boundary header

View Source
var ErrPartialWrite = errors.New("Failed to write full body")

ErrPartialWrite happens when the full body can't be written

View Source
var MaximumMultipartDepth = 10

Most emails will never contain more than 3 levels of nested multipart bodies

View Source
var MaximumPartsPerMultipart = 50

Most emails will never have more than a dozen attachments / text parts total

Functions

func CreateQuotedPart

func CreateQuotedPart(writer *multipart.Writer, contentType string) (w *quotedprintable.Writer, err error)

CreateQuotedPart creates a quoted-printable, wrapped, mime part

func HandleEmailFromReader

func HandleEmailFromReader(r io.Reader, h partHandler) (err error)

NewEmailFromReader reads a stream of bytes from an io.Reader, r, and returns an email struct containing the parsed data. This function expects the data in RFC 5322 format.

func NewMimeBase64Writer

func NewMimeBase64Writer(w io.Writer) io.WriteCloser

NewMimeBase64Writer base64 encodes content and wraps to 76 characters

func ToASCII

func ToASCII(s string) string

ToASCII converts unicode to ASCII by stripping accents and converting some special characters into their ASCII approximations. Anything else will be replaced with an underscore.

Types

type Alternative

type Alternative struct {
	Parts Parts
}

Alternative multipart/mime part

func (Alternative) Add

func (p Alternative) Add(w *multipart.Writer) (err error)

type File

type File struct {
	// Name is the basename name of the file
	Name string

	// Optional, will be detected by File.Name extension
	ContentType string

	// Include Inline, or as an Attachment (default)?
	Inline bool

	// Character set to use (defaults to utf-8)
	Charset string

	// Reader is the data source that the part is populated from.
	io.Reader

	// Closer is an optional io.Closer that is called after reading the Reader
	io.Closer
}

File is a multipart implementation for files read from an io.Reader.

func (File) Add

func (f File) Add(w *multipart.Writer) (err error)

Add implements the Source interface.

type Mixed

type Mixed struct {
	Parts Parts
}

Mixed multipart/mime part

func (Mixed) Add

func (p Mixed) Add(w *multipart.Writer) (err error)

type Part

type Part interface {
	// Name can be a field name or content type. It is the part Content-Type
	Add(w *multipart.Writer) error
}

Part defines a named part inside of a multipart message. Part is a data source that can add itself to a mime/multipart.Writer.

type Parts

type Parts []Part

Parts is a collection of parts of a multipart message.

func (Parts) Into

func (p Parts) Into(w *multipart.Writer) (err error)

Into the given multipart.Writer

type Text

type Text struct {
	ContentType string
	Text        string
}

Text is a text/HTML/other content body part

func (Text) Add

func (p Text) Add(w *multipart.Writer) error

Add implements the Source interface.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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