func (h *Header) GenerateMessageID() error {
	now := uint64(time.Now().UnixNano())
	nonceByte := make([]byte, 8)
	if _, err := rand.Read(nonceByte); err != nil {
		return err
	}
	nonce := binary.BigEndian.Uint64(nonceByte)
	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	msgID := fmt.Sprintf("%s.%s@%s", base36(now), base36(nonce), hostname)
	h.SetMessageID(msgID)
	return nil
}
GenerateMessageID generates an RFC 2822-compliant Message-Id based on the
informational draft "Recommendations for generating Message IDs", for lack
of a better authoritative source.
package mail
import (
	"crypto/rand"
	"encoding/binary"
	"errors"
	"fmt"
	"net/mail"
	"os"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
	"github.com/emersion/go-message"
)
const dateLayout = "Mon, 02 Jan 2006 15:04:05 -0700"
type headerParser struct {
	s string
}
func (p *headerParser) len() int {
	return len(p.s)
}
func (p *headerParser) empty() bool {
	return p.len() == 0
}
func (p *headerParser) peek() byte {
	return p.s[0]
}
func (p *headerParser) consume(c byte) bool {
	if p.empty() || p.peek() != c {
		return false
	}
	p.s = p.s[1:]
	return true
}
func (p *headerParser) skipSpace() {
	p.s = strings.TrimLeft(p.s, " \t")
}
func (p *headerParser) skipCFWS() bool {
	p.skipSpace()
	for {
		if !p.consume('(') {
			break
		}
		if _, ok := p.consumeComment(); !ok {
			return false
		}
		p.skipSpace()
	}
	return true
}
func (p *headerParser) consumeComment() (string, bool) {
	depth := 1
	var comment string
	for {
		if p.empty() || depth == 0 {
			break
		}
		if p.peek() == '\\' && p.len() > 1 {
			p.s = p.s[1:]
		} else if p.peek() == '(' {
			depth++
		} else if p.peek() == ')' {
			depth--
		}
		if depth > 0 {
			comment += p.s[:1]
		}
		p.s = p.s[1:]
	}
	return comment, depth == 0
}
func (p *headerParser) parseAtomText(dot bool) (string, error) {
	i := 0
	for {
		r, size := utf8.DecodeRuneInString(p.s[i:])
		if size == 1 && r == utf8.RuneError {
			return "", fmt.Errorf("mail: invalid UTF-8 in atom-text: %q", p.s)
		} else if size == 0 || !isAtext(r, dot) {
			break
		}
		i += size
	}
	if i == 0 {
		return "", errors.New("mail: invalid string")
	}
	var atom string
	atom, p.s = p.s[:i], p.s[i:]
	return atom, nil
}
func isAtext(r rune, dot bool) bool {
	switch r {
	case '.':
		return dot
	case '(', ')', '[', ']', ';', '@', '\\', ',':
		return false
	case '<', '>', '"', ':':
		return false
	}
	return isVchar(r)
}
func isVchar(r rune) bool {
	return '!' <= r && r <= '~' || isMultibyte(r)
}
func isMultibyte(r rune) bool {
	return r >= utf8.RuneSelf
}
func (p *headerParser) parseNoFoldLiteral() (string, error) {
	if !p.consume('[') {
		return "", errors.New("mail: missing '[' in no-fold-literal")
	}
	i := 0
	for {
		r, size := utf8.DecodeRuneInString(p.s[i:])
		if size == 1 && r == utf8.RuneError {
			return "", fmt.Errorf("mail: invalid UTF-8 in no-fold-literal: %q", p.s)
		} else if size == 0 || !isDtext(r) {
			break
		}
		i += size
	}
	var lit string
	lit, p.s = p.s[:i], p.s[i:]
	if !p.consume(']') {
		return "", errors.New("mail: missing ']' in no-fold-literal")
	}
	return "[" + lit + "]", nil
}
func isDtext(r rune) bool {
	switch r {
	case '[', ']', '\\':
		return false
	}
	return isVchar(r)
}
func (p *headerParser) parseMsgID() (string, error) {
	if !p.skipCFWS() {
		return "", errors.New("mail: malformed parenthetical comment")
	}
	if !p.consume('<') {
		return "", errors.New("mail: missing '<' in msg-id")
	}
	left, err := p.parseAtomText(true)
	if err != nil {
		return "", err
	}
	if !p.consume('@') {
		return "", errors.New("mail: missing '@' in msg-id")
	}
	var right string
	if !p.empty() && p.peek() == '[' {
		right, err = p.parseNoFoldLiteral()
	} else {
		right, err = p.parseAtomText(true)
		if err != nil {
			return "", err
		}
	}
	if !p.consume('>') {
		return "", errors.New("mail: missing '>' in msg-id")
	}
	if !p.skipCFWS() {
		return "", errors.New("mail: malformed parenthetical comment")
	}
	return left + "@" + right, nil
}
type Header struct {
	message.Header
}
func HeaderFromMap(m map[string][]string) Header {
	return Header{message.HeaderFromMap(m)}
}
func (h *Header) AddressList(key string) ([]*Address, error) {
	v := h.Get(key)
	if v == "" {
		return nil, nil
	}
	return ParseAddressList(v)
}
func (h *Header) SetAddressList(key string, addrs []*Address) {
	h.Set(key, formatAddressList(addrs))
}
func (h *Header) Date() (time.Time, error) {
	return mail.ParseDate(h.Get("Date"))
}
func (h *Header) SetDate(t time.Time) {
	h.Set("Date", t.Format(dateLayout))
}
func (h *Header) Subject() (string, error) {
	return h.Text("Subject")
}
func (h *Header) SetSubject(s string) {
	h.SetText("Subject", s)
}
func (h *Header) MessageID() (string, error) {
	v := h.Get("Message-Id")
	if v == "" {
		return "", nil
	}
	p := headerParser{v}
	return p.parseMsgID()
}
func (h *Header) MsgIDList(key string) ([]string, error) {
	v := h.Get(key)
	if v == "" {
		return nil, nil
	}
	p := headerParser{v}
	var l []string
	for !p.empty() {
		msgID, err := p.parseMsgID()
		if err != nil {
			return l, err
		}
		l = append(l, msgID)
	}
	return l, nil
}