email

package
v0.0.0-...-d31700d Latest Latest
Warning

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

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

README

email

Feature

  • connection pool (maxOpen/maxIdle).
  • connection usability check.
  • implict tls (net/smtp uses explict StartTLS, which is vulnerable).

Documentation

Index

Examples

Constants

View Source
const (
	// BEncoding represents Base64 encoding scheme as defined by RFC 2045.
	BEncoding = WordEncoder('b')
	// QEncoding represents the Q-encoding scheme as defined by RFC 2047.
	QEncoding = WordEncoder('q')
)
View Source
const (
	MIMEVersion             = "MIME-Version"
	ContentType             = "Content-Type"
	ContentTransferEncoding = "Content-Transfer-Encoding"
	ContentDisposition      = "Content-Disposition"
	ContentDescription      = "Content-Description"

	From = "From"
	To   = "To"
	Cc   = "Cc"
	Bcc  = "Bcc"

	Subject = "Subject"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}
Example
client, err := NewClient(testUrl)
if err != nil {
	panic(err)
}

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// send simple email
err = client.Send(ctx, &Message{
	Headers: []Header{
		{Name: To, Values: []string{"测试收件人<" + testTo + ">"}},
		{Name: Subject, Values: []string{"测试Simple"}},
		{Name: ContentType, Values: []string{"text/html; charset=utf-8"}},
	},
	Body: []byte("<h1>测试内容</h1>"),
})
if err != nil {
	fmt.Println(err)
}

// send multipart email
err = client.Send(ctx, &Message{
	Headers: []Header{
		{Name: To, Values: []string{"测试收件人<" + testTo + ">"}},
		{Name: Subject, Values: []string{"测试Multipart"}},
	},
	BodyParts: []Message{
		{
			Headers: []Header{
				{Name: ContentType, Values: []string{"text/html; charset=utf-8"}},
			},
			Body: []byte(`<h1>测试内容:含附件。</h1>`),
		},
		{
			Headers: []Header{
				{Name: ContentType, Values: []string{"text/plain; charset=utf-8"}},
				{Name: ContentDisposition, Values: []string{`attachment; filename="file.txt"`}},
			},
			Body: []byte("这是附件内容。"),
		},
	},
})
if err != nil {
	fmt.Println(err)
}
Output:

func NewClient

func NewClient(urlString string) (*Client, error)

NewClient make a Client from a url config. urlString example: smtp://stmp.exmail.qq.com:465/?user=张三<zhangsan@example.com>&pass=password urlString have 3 optional query params:

  1. maxOpen: Max number of connections can open at a time. Default value is 10.
  2. maxIdle: Max number of idle connections to keep. Default value is 1.
  3. safeIdleTime: A time.Duration string. If a connection has been idle greater than the safe time,

it will be checked by a noop operation to ensure it's not closed by the server side. Default value is 30s.

func (*Client) Send

func (c *Client) Send(ctx context.Context, msg *Message) (err error)

type Conn

type Conn struct {
	*smtp.Client
	// contains filtered or unexported fields
}

func Dial

func Dial(ctx context.Context, addr string, auth smtp.Auth) (*Conn, error)

func (*Conn) Send

func (c *Conn) Send(ctx context.Context, from string, to []string, msg []byte) (err error)
Example
package main

import (
	"context"
	"fmt"
	"net/smtp"
	"time"
)

const (
	testHost = "smtp.qq.com"
	testPort = "465"
	testFrom = "xiaomei-go@qq.com"
	testPass = "eyunewumzlywdicd"
	testTo   = "applejava@qq.com"
)

var testUrl = fmt.Sprintf("smtp://%s:%s?user=%s&pass=%s", testHost, testPort, testFrom, testPass)

func main() {

	const content = "From: " + testFrom + "\n" +
		"To: " + testTo + "\n" +
		"Subject: test subject\n" +
		"\n" +
		"test body line1.\n" +
		"test body line2.\n"

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	conn, err := Dial(ctx, testHost+":"+testPort, smtp.PlainAuth("", testFrom, testPass, testHost))
	if err != nil {
		panic(err)
	}

	if err := conn.Send(ctx, testFrom, []string{testTo}, []byte(content)); err != nil {
		fmt.Println(err)
	}

	if err := conn.Send(ctx, testFrom, []string{testTo}, []byte(content)); err != nil {
		fmt.Println(err)
	}

}
Output:

type Header struct {
	Name   string
	Values []string
}

type LineWriter

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

LineWriter add "\n" after every 76 bytes.

func NewLineWriter

func NewLineWriter(w io.Writer) *LineWriter

func (*LineWriter) Write

func (lw *LineWriter) Write(b []byte) (total int, err error)

type Message

type Message struct {
	Headers   []Header
	Body      []byte    // body for Content-Type: plain, image, audio, video or application.
	BodyParts []Message // body for Content-Type: multipart or message.
}

Message implements Internet Message as defined in RFC2822 and RFC2045 ~ RFC2049.

Example
const longContent = "我们中国人民从此站立起来了!We Chinese People Stand Up From Now!"
m := Message{
	Headers: []Header{
		{Name: From, Values: []string{"测试来源<applejava@qq.com>"}},
		{Name: To, Values: []string{"测试收件人<applejava@qq.com>"}},
		{Name: Subject, Values: []string{"测试主题:" + longContent}},
	},
	Body: []byte("测试内容:" + longContent),
}
if recipients, err := getRecipients(m.Headers); err != nil {
	fmt.Println(err)
} else {
	fmt.Println(recipients)
}
if body, err := m.Bytes(); err != nil {
	fmt.Println(err)
} else {
	fmt.Println(string(body))
}
Output:

[applejava@qq.com]
From: =?utf-8?b?5rWL6K+V5p2l5rqQ?= <applejava@qq.com>
To: =?utf-8?b?5rWL6K+V5pS25Lu25Lq6?= <applejava@qq.com>
Subject: =?utf-8?b?5rWL6K+V5Li76aKY77ya5oiR5Lus5Lit5Zu95Lq65rCR5LuO5q2k56uZ56uL?=
 =?utf-8?b?6LW35p2l5LqG77yBV2UgQ2hpbmVzZSBQZW9wbGUgU3RhbmQgVXAgRnJvbSBO?=
 =?utf-8?b?b3ch?=
MIME-Version: 1.0
Content-Transfer-Encoding: base64

5rWL6K+V5YaF5a6577ya5oiR5Lus5Lit5Zu95Lq65rCR5LuO5q2k56uZ56uL6LW35p2l5LqG77yB
V2UgQ2hpbmVzZSBQZW9wbGUgU3RhbmQgVXAgRnJvbSBOb3ch

func (*Message) Bytes

func (m *Message) Bytes() ([]byte, error)

Bytes is the most important entrance func, it calls all the logic to convert a Message to bytes.

func (*Message) IsMultipart

func (m *Message) IsMultipart() bool

IsMultipart return if this is a multipart message.

type WordDecoder

type WordDecoder struct {
	// CharsetReader, if non-nil, defines a function to generate
	// charset-conversion readers, converting from the provided
	// charset into UTF-8.
	// Charsets are always lower-case. utf-8, iso-8859-1 and us-ascii charsets
	// are handled by default.
	// One of the CharsetReader's result values must be non-nil.
	CharsetReader func(charset string, input io.Reader) (io.Reader, error)
}

A WordDecoder decodes MIME headers containing RFC 2047 encoded-words.

func (*WordDecoder) Decode

func (d *WordDecoder) Decode(word string) (string, error)

Decode decodes an RFC 2047 encoded-word.

func (*WordDecoder) DecodeHeader

func (d *WordDecoder) DecodeHeader(header string) (string, error)

DecodeHeader decodes all encoded-words of the given string. It returns an error if and only if CharsetReader of d returns an error.

type WordEncoder

type WordEncoder byte

A WordEncoder is an RFC 2047 encoded-word encoder.

func (WordEncoder) Encode

func (e WordEncoder) Encode(charset, s string) string

Encode returns the encoded-word form of s. If s is ASCII without special characters, it is returned unchanged. The provided charset is the IANA charset name of s. It is case insensitive.

Jump to

Keyboard shortcuts

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