Switching to maintained gomail fork.
Этот коммит содержится в:
14
Gopkg.lock
сгенерированный
14
Gopkg.lock
сгенерированный
@@ -587,7 +587,7 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:9ea97158ea06d60b1f324aa384f6a4cbd596a81b3cae994e17108b195f398d01"
|
digest = "1:d39e7c7677b161c2dd4c635a2ac196460608c7d8ba5337cc8cae5825a2681f8f"
|
||||||
name = "github.com/prometheus/procfs"
|
name = "github.com/prometheus/procfs"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@@ -596,7 +596,7 @@
|
|||||||
"xfs",
|
"xfs",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "aa55a523dc0a8297edf51bb75e8eec13eb3be45d"
|
revision = "1dc9a6cbc91aacc3e8b2d63db4d2e957a5394ac4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758"
|
digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758"
|
||||||
@@ -952,12 +952,12 @@
|
|||||||
version = "v1.3"
|
version = "v1.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:eebd52aee67d9f1e0af1859a584e14b1817581dd5f90d4585418c27b6a93c966"
|
digest = "1:3806f369b846160fcbde19bdcf93790868defe7c58d1bb6bc8d974c5b8f8dc1e"
|
||||||
name = "gopkg.in/gomail.v2"
|
name = "gopkg.in/mail.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "41f3572897373c5538c50a2402db15db079fa4fd"
|
revision = "f59b9b83a4e522098e3d3eb94e6f81850ad6e973"
|
||||||
version = "2.0.0"
|
version = "v2.3.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c805e517269b0ba4c21ded5836019ed7d16953d4026cb7d00041d039c7906be9"
|
digest = "1:c805e517269b0ba4c21ded5836019ed7d16953d4026cb7d00041d039c7906be9"
|
||||||
@@ -1047,7 +1047,7 @@
|
|||||||
"golang.org/x/crypto/bcrypt",
|
"golang.org/x/crypto/bcrypt",
|
||||||
"golang.org/x/image/bmp",
|
"golang.org/x/image/bmp",
|
||||||
"golang.org/x/net/html/charset",
|
"golang.org/x/net/html/charset",
|
||||||
"gopkg.in/gomail.v2",
|
"gopkg.in/mail.v2",
|
||||||
"gopkg.in/natefinch/lumberjack.v2",
|
"gopkg.in/natefinch/lumberjack.v2",
|
||||||
"gopkg.in/olivere/elastic.v5",
|
"gopkg.in/olivere/elastic.v5",
|
||||||
"gopkg.in/yaml.v2",
|
"gopkg.in/yaml.v2",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"net/smtp"
|
"net/smtp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/gomail.v2"
|
gomail "gopkg.in/mail.v2"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
|||||||
3
vendor/github.com/prometheus/procfs/Makefile
сгенерированный
поставляемый
3
vendor/github.com/prometheus/procfs/Makefile
сгенерированный
поставляемый
@@ -23,5 +23,8 @@ update_fixtures: fixtures.ttar sysfs/fixtures.ttar
|
|||||||
rm -v $(dir $*)fixtures/.unpacked
|
rm -v $(dir $*)fixtures/.unpacked
|
||||||
./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/
|
./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test
|
test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test
|
||||||
|
|||||||
8
vendor/gopkg.in/gomail.v2/.travis.yml
сгенерированный
поставляемый
8
vendor/gopkg.in/gomail.v2/.travis.yml
сгенерированный
поставляемый
@@ -1,8 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.2
|
|
||||||
- 1.3
|
|
||||||
- 1.4
|
|
||||||
- 1.5
|
|
||||||
- tip
|
|
||||||
20
vendor/gopkg.in/gomail.v2/CHANGELOG.md
сгенерированный
поставляемый
20
vendor/gopkg.in/gomail.v2/CHANGELOG.md
сгенерированный
поставляемый
@@ -1,20 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
||||||
|
|
||||||
## [2.0.0] - 2015-09-02
|
|
||||||
|
|
||||||
- Mailer has been removed. It has been replaced by Dialer and Sender.
|
|
||||||
- `File` type and the `CreateFile` and `OpenFile` functions have been removed.
|
|
||||||
- `Message.Attach` and `Message.Embed` have a new signature.
|
|
||||||
- `Message.GetBodyWriter` has been removed. Use `Message.AddAlternativeWriter`
|
|
||||||
instead.
|
|
||||||
- `Message.Export` has been removed. `Message.WriteTo` can be used instead.
|
|
||||||
- `Message.DelHeader` has been removed.
|
|
||||||
- The `Bcc` header field is no longer sent. It is far more simpler and
|
|
||||||
efficient: the same message is sent to all recipients instead of sending a
|
|
||||||
different email to each Bcc address.
|
|
||||||
- LoginAuth has been removed. `NewPlainDialer` now implements the LOGIN
|
|
||||||
authentication mechanism when needed.
|
|
||||||
- Go 1.2 is now required instead of Go 1.3. No external dependency are used when
|
|
||||||
using Go 1.5.
|
|
||||||
97
vendor/gopkg.in/gomail.v2/README.md
сгенерированный
поставляемый
97
vendor/gopkg.in/gomail.v2/README.md
сгенерированный
поставляемый
@@ -1,97 +0,0 @@
|
|||||||
# Gomail
|
|
||||||
[](https://travis-ci.org/go-gomail/gomail) [](http://gocover.io/gopkg.in/gomail.v2) [](https://godoc.org/gopkg.in/gomail.v2)
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Gomail is a simple and efficient package to send emails. It is well tested and
|
|
||||||
documented.
|
|
||||||
|
|
||||||
It is versioned using [gopkg.in](https://gopkg.in) so I promise
|
|
||||||
they will never be backward incompatible changes within each version.
|
|
||||||
|
|
||||||
It requires Go 1.2 or newer. With Go 1.5, no external dependencies are used.
|
|
||||||
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
Gomail supports:
|
|
||||||
- Attachments
|
|
||||||
- Embedded images
|
|
||||||
- HTML and text templates
|
|
||||||
- Automatic encoding of special characters
|
|
||||||
- SSL and TLS
|
|
||||||
- Sending multiple emails with the same SMTP connection
|
|
||||||
- Any method to send emails: SMTP, postfix (not included but easily doable), etc
|
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
https://godoc.org/gopkg.in/gomail.v2
|
|
||||||
|
|
||||||
|
|
||||||
## Download
|
|
||||||
|
|
||||||
go get gopkg.in/gomail.v2
|
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
See the [examples in the documentation](https://godoc.org/gopkg.in/gomail.v2#example-package).
|
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
### x509: certificate signed by unknown authority
|
|
||||||
|
|
||||||
If you get this error it means the certificate used by the SMTP server is not
|
|
||||||
considered valid by the client running Gomail. As a quick workaround you can
|
|
||||||
bypass the verification of the server's certificate chain and host name by using
|
|
||||||
`SetTLSConfig`:
|
|
||||||
|
|
||||||
d := gomail.NewPlainDialer("smtp.example.com", "user", "123456", 587)
|
|
||||||
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
|
||||||
|
|
||||||
Note, however, that this is insecure and should not be used in production.
|
|
||||||
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
Contributions are more than welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for
|
|
||||||
more info.
|
|
||||||
|
|
||||||
|
|
||||||
## Change log
|
|
||||||
|
|
||||||
See [CHANGELOG.md](CHANGELOG.md).
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[MIT](LICENSE)
|
|
||||||
|
|
||||||
|
|
||||||
## Contact
|
|
||||||
|
|
||||||
You can ask questions on the [Gomail
|
|
||||||
thread](https://groups.google.com/d/topic/golang-nuts/jMxZHzvvEVg/discussion)
|
|
||||||
in the Go mailing-list.
|
|
||||||
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
If you want to support the development of Gomail, I gladly accept donations.
|
|
||||||
|
|
||||||
I will give 100% of the money I receive to
|
|
||||||
[Enfants, Espoir Du Monde](http://www.eedm.fr/).
|
|
||||||
EEDM is a French NGO which helps children in Bangladesh, Cameroun, Haiti, India
|
|
||||||
and Madagascar.
|
|
||||||
|
|
||||||
All its members are volunteers so its operating costs are only
|
|
||||||
1.9%. So your money will directly helps children of these countries.
|
|
||||||
|
|
||||||
As an added bonus, your donations will also tip me by lowering my taxes :smile:
|
|
||||||
|
|
||||||
I will send an email with the receipt of the donation to EEDM annually to all
|
|
||||||
donors.
|
|
||||||
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PYQKC7VFVXCFG)
|
|
||||||
67
vendor/gopkg.in/gomail.v2/auth.go
сгенерированный
поставляемый
67
vendor/gopkg.in/gomail.v2/auth.go
сгенерированный
поставляемый
@@ -1,67 +0,0 @@
|
|||||||
package gomail
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/smtp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// plainAuth is an smtp.Auth that implements the PLAIN authentication mechanism.
|
|
||||||
// It fallbacks to the LOGIN mechanism if it is the only mechanism advertised
|
|
||||||
// by the server.
|
|
||||||
type plainAuth struct {
|
|
||||||
username string
|
|
||||||
password string
|
|
||||||
host string
|
|
||||||
login bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *plainAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
|
||||||
if server.Name != a.host {
|
|
||||||
return "", nil, errors.New("gomail: wrong host name")
|
|
||||||
}
|
|
||||||
|
|
||||||
var plain, login bool
|
|
||||||
for _, a := range server.Auth {
|
|
||||||
switch a {
|
|
||||||
case "PLAIN":
|
|
||||||
plain = true
|
|
||||||
case "LOGIN":
|
|
||||||
login = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !server.TLS && !plain && !login {
|
|
||||||
return "", nil, errors.New("gomail: unencrypted connection")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !plain && login {
|
|
||||||
a.login = true
|
|
||||||
return "LOGIN", nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "PLAIN", []byte("\x00" + a.username + "\x00" + a.password), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
|
||||||
if !a.login {
|
|
||||||
if more {
|
|
||||||
return nil, errors.New("gomail: unexpected server challenge")
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !more {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case bytes.Equal(fromServer, []byte("Username:")):
|
|
||||||
return []byte(a.username), nil
|
|
||||||
case bytes.Equal(fromServer, []byte("Password:")):
|
|
||||||
return []byte(a.password), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("gomail: unexpected server challenge: %s", fromServer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
16
vendor/gopkg.in/gomail.v2/mime_go14.go
сгенерированный
поставляемый
16
vendor/gopkg.in/gomail.v2/mime_go14.go
сгенерированный
поставляемый
@@ -1,16 +0,0 @@
|
|||||||
// +build !go1.5
|
|
||||||
|
|
||||||
package gomail
|
|
||||||
|
|
||||||
import "gopkg.in/alexcesaro/quotedprintable.v3"
|
|
||||||
|
|
||||||
var newQPWriter = quotedprintable.NewWriter
|
|
||||||
|
|
||||||
type mimeEncoder struct {
|
|
||||||
quotedprintable.WordEncoder
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
bEncoding = mimeEncoder{quotedprintable.BEncoding}
|
|
||||||
qEncoding = mimeEncoder{quotedprintable.QEncoding}
|
|
||||||
)
|
|
||||||
175
vendor/gopkg.in/gomail.v2/smtp.go
сгенерированный
поставляемый
175
vendor/gopkg.in/gomail.v2/smtp.go
сгенерированный
поставляемый
@@ -1,175 +0,0 @@
|
|||||||
package gomail
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/smtp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Dialer is a dialer to an SMTP server.
|
|
||||||
type Dialer struct {
|
|
||||||
// Host represents the host of the SMTP server.
|
|
||||||
Host string
|
|
||||||
// Port represents the port of the SMTP server.
|
|
||||||
Port int
|
|
||||||
// Auth represents the authentication mechanism used to authenticate to the
|
|
||||||
// SMTP server.
|
|
||||||
Auth smtp.Auth
|
|
||||||
// SSL defines whether an SSL connection is used. It should be false in
|
|
||||||
// most cases since the authentication mechanism should use the STARTTLS
|
|
||||||
// extension instead.
|
|
||||||
SSL bool
|
|
||||||
// TSLConfig represents the TLS configuration used for the TLS (when the
|
|
||||||
// STARTTLS extension is used) or SSL connection.
|
|
||||||
TLSConfig *tls.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPlainDialer returns a Dialer. The given parameters are used to connect to
|
|
||||||
// the SMTP server via a PLAIN authentication mechanism.
|
|
||||||
//
|
|
||||||
// It fallbacks to the LOGIN mechanism if it is the only mechanism advertised by
|
|
||||||
// the server.
|
|
||||||
func NewPlainDialer(host string, port int, username, password string) *Dialer {
|
|
||||||
return &Dialer{
|
|
||||||
Host: host,
|
|
||||||
Port: port,
|
|
||||||
Auth: &plainAuth{
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
host: host,
|
|
||||||
},
|
|
||||||
SSL: port == 465,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial dials and authenticates to an SMTP server. The returned SendCloser
|
|
||||||
// should be closed when done using it.
|
|
||||||
func (d *Dialer) Dial() (SendCloser, error) {
|
|
||||||
c, err := d.dial()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.Auth != nil {
|
|
||||||
if ok, _ := c.Extension("AUTH"); ok {
|
|
||||||
if err = c.Auth(d.Auth); err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &smtpSender{c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) dial() (smtpClient, error) {
|
|
||||||
if d.SSL {
|
|
||||||
return d.sslDial()
|
|
||||||
}
|
|
||||||
return d.starttlsDial()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) starttlsDial() (smtpClient, error) {
|
|
||||||
c, err := smtpDial(addr(d.Host, d.Port))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok, _ := c.Extension("STARTTLS"); ok {
|
|
||||||
if err := c.StartTLS(d.tlsConfig()); err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) sslDial() (smtpClient, error) {
|
|
||||||
conn, err := tlsDial("tcp", addr(d.Host, d.Port), d.tlsConfig())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newClient(conn, d.Host)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) tlsConfig() *tls.Config {
|
|
||||||
if d.TLSConfig == nil {
|
|
||||||
return &tls.Config{ServerName: d.Host}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.TLSConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func addr(host string, port int) string {
|
|
||||||
return fmt.Sprintf("%s:%d", host, port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialAndSend opens a connection to the SMTP server, sends the given emails and
|
|
||||||
// closes the connection.
|
|
||||||
func (d *Dialer) DialAndSend(m ...*Message) error {
|
|
||||||
s, err := d.Dial()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
return Send(s, m...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type smtpSender struct {
|
|
||||||
smtpClient
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
|
|
||||||
if err := c.Mail(from); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range to {
|
|
||||||
if err := c.Rcpt(addr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err := c.Data()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = msg.WriteTo(w); err != nil {
|
|
||||||
w.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *smtpSender) Close() error {
|
|
||||||
return c.Quit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stubbed out for tests.
|
|
||||||
var (
|
|
||||||
smtpDial = func(addr string) (smtpClient, error) {
|
|
||||||
return smtp.Dial(addr)
|
|
||||||
}
|
|
||||||
tlsDial = tls.Dial
|
|
||||||
newClient = func(conn net.Conn, host string) (smtpClient, error) {
|
|
||||||
return smtp.NewClient(conn, host)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type smtpClient interface {
|
|
||||||
Extension(string) (bool, string)
|
|
||||||
StartTLS(*tls.Config) error
|
|
||||||
Auth(smtp.Auth) error
|
|
||||||
Mail(string) error
|
|
||||||
Rcpt(string) error
|
|
||||||
Data() (io.WriteCloser, error)
|
|
||||||
Quit() error
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
17
vendor/gopkg.in/mail.v2/.gitignore
сгенерированный
поставляемый
Обычный файл
17
vendor/gopkg.in/mail.v2/.gitignore
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
|
||||||
|
# IDE's
|
||||||
|
.idea/
|
||||||
25
vendor/gopkg.in/mail.v2/.travis.yml
сгенерированный
поставляемый
Обычный файл
25
vendor/gopkg.in/mail.v2/.travis.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,25 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
- 1.8
|
||||||
|
- 1.9
|
||||||
|
- master
|
||||||
|
|
||||||
|
# safelist
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- v2
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- mkdir -p $GOPATH/src/gopkg.in &&
|
||||||
|
ln -s ../github.com/go-mail/mail $GOPATH/src/gopkg.in/mail.v2
|
||||||
88
vendor/gopkg.in/mail.v2/CHANGELOG.md
сгенерированный
поставляемый
Обычный файл
88
vendor/gopkg.in/mail.v2/CHANGELOG.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,88 @@
|
|||||||
|
# Change Log
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## *Unreleased*
|
||||||
|
|
||||||
|
## [2.3.1] - 2018-11-12
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #39: Reverts addition of Go modules `go.mod` manifest.
|
||||||
|
|
||||||
|
## [2.3.0] - 2018-11-10
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #12: Adds `SendError` to provide additional info about the cause and index of
|
||||||
|
a failed attempt to transmit a batch of messages.
|
||||||
|
- go-gomail#78: Adds new `Message` methods for attaching and embedding
|
||||||
|
`io.Reader`s: `AttachReader` and `EmbedReader`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #26: Fixes RFC 1341 compliance by properly capitalizing the
|
||||||
|
`MIME-Version` header.
|
||||||
|
- #30: Fixes IO errors being silently dropped in `Message.WriteTo`.
|
||||||
|
|
||||||
|
## [2.2.0] - 2018-03-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #20: Adds `Message.SetBoundary` to allow specifying a custom MIME boundary.
|
||||||
|
- #22: Adds `Message.SetBodyWriter` to make it easy to use text/template and
|
||||||
|
html/template for message bodies. Contributed by Quantcast.
|
||||||
|
- #25: Adds `Dialer.StartTLSPolicy` so that `MandatoryStartTLS` can be required,
|
||||||
|
or `NoStartTLS` can disable it. Contributed by Quantcast.
|
||||||
|
|
||||||
|
## [2.1.0] - 2017-12-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- go-gomail#40: Adds `Dialer.LocalName` field to allow specifying the hostname
|
||||||
|
sent with SMTP's HELO command.
|
||||||
|
- go-gomail#47: `Message.SetBody`, `Message.AddAlternative`, and
|
||||||
|
`Message.AddAlternativeWriter` allow specifying the encoding of message parts.
|
||||||
|
- `Dialer.Dial`'s returned `SendCloser` automatically redials after a timeout.
|
||||||
|
- go-gomail#55, go-gomail#56: Adds `Rename` to allow specifying filename
|
||||||
|
of an attachment.
|
||||||
|
- go-gomail#100: Exports `NetDialTimeout` to allow setting a custom dialer.
|
||||||
|
- go-gomail#70: Adds `Dialer.Timeout` field to allow specifying a timeout for
|
||||||
|
dials, reads, and writes.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- go-gomail#52: `Dialer.Dial` automatically uses CRAM-MD5 when available.
|
||||||
|
- `Dialer.Dial` specifies a default timeout of 10 seconds.
|
||||||
|
- Gomail is forked from <https://github.com/go-gomail/gomail/> to
|
||||||
|
<https://github.com/go-mail/mail/>.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- go-gomail#52: `NewPlainDialer` is deprecated in favor of `NewDialer`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- go-gomail#41, go-gomail#42: Fixes a panic when a `Message` contains a
|
||||||
|
nil header.
|
||||||
|
- go-gomail#44: Fixes `AddAlternativeWriter` replacing the message body instead
|
||||||
|
of adding a body part.
|
||||||
|
- go-gomail#53: Folds long header lines for RFC 2047 compliance.
|
||||||
|
- go-gomail#54: Fixes `Message.FormatAddress` when name is blank.
|
||||||
|
|
||||||
|
## [2.0.0] - 2015-09-02
|
||||||
|
|
||||||
|
- Mailer has been removed. It has been replaced by Dialer and Sender.
|
||||||
|
- `File` type and the `CreateFile` and `OpenFile` functions have been removed.
|
||||||
|
- `Message.Attach` and `Message.Embed` have a new signature.
|
||||||
|
- `Message.GetBodyWriter` has been removed. Use `Message.AddAlternativeWriter`
|
||||||
|
instead.
|
||||||
|
- `Message.Export` has been removed. `Message.WriteTo` can be used instead.
|
||||||
|
- `Message.DelHeader` has been removed.
|
||||||
|
- The `Bcc` header field is no longer sent. It is far more simpler and
|
||||||
|
efficient: the same message is sent to all recipients instead of sending a
|
||||||
|
different email to each Bcc address.
|
||||||
|
- LoginAuth has been removed. `NewPlainDialer` now implements the LOGIN
|
||||||
|
authentication mechanism when needed.
|
||||||
|
- Go 1.2 is now required instead of Go 1.3. No external dependency are used when
|
||||||
|
using Go 1.5.
|
||||||
0
vendor/gopkg.in/gomail.v2/CONTRIBUTING.md → vendor/gopkg.in/mail.v2/CONTRIBUTING.md
сгенерированный
поставляемый
0
vendor/gopkg.in/gomail.v2/CONTRIBUTING.md → vendor/gopkg.in/mail.v2/CONTRIBUTING.md
сгенерированный
поставляемый
0
vendor/gopkg.in/gomail.v2/LICENSE → vendor/gopkg.in/mail.v2/LICENSE
сгенерированный
поставляемый
0
vendor/gopkg.in/gomail.v2/LICENSE → vendor/gopkg.in/mail.v2/LICENSE
сгенерированный
поставляемый
129
vendor/gopkg.in/mail.v2/README.md
сгенерированный
поставляемый
Обычный файл
129
vendor/gopkg.in/mail.v2/README.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,129 @@
|
|||||||
|
# Gomail
|
||||||
|
[](https://travis-ci.org/go-mail/mail) [](http://gocover.io/github.com/go-mail/mail) [](https://godoc.org/github.com/go-mail/mail)
|
||||||
|
|
||||||
|
This is an actively maintained fork of [Gomail][1] and includes fixes and
|
||||||
|
improvements for a number of outstanding issues. The current progress is
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
- [x] Timeouts and retries can be specified outside of the 10 second default.
|
||||||
|
- [x] Proxying is supported through specifying a custom [NetDialTimeout][2].
|
||||||
|
- [ ] Filenames are properly encoded for non-ASCII characters.
|
||||||
|
- [ ] Email addresses are properly encoded for non-ASCII characters.
|
||||||
|
- [ ] Embedded files and attachments are tested for their existence.
|
||||||
|
- [ ] An `io.Reader` can be supplied when embedding and attaching files.
|
||||||
|
|
||||||
|
See [Transitioning Existing Codebases][3] for more information on switching.
|
||||||
|
|
||||||
|
[1]: https://github.com/go-gomail/gomail
|
||||||
|
[2]: https://godoc.org/gopkg.in/mail.v2#NetDialTimeout
|
||||||
|
[3]: #transitioning-existing-codebases
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Gomail is a simple and efficient package to send emails. It is well tested and
|
||||||
|
documented.
|
||||||
|
|
||||||
|
Gomail can only send emails using an SMTP server. But the API is flexible and it
|
||||||
|
is easy to implement other methods for sending emails using a local Postfix, an
|
||||||
|
API, etc.
|
||||||
|
|
||||||
|
It requires Go 1.2 or newer. With Go 1.5, no external dependencies are used.
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Gomail supports:
|
||||||
|
- Attachments
|
||||||
|
- Embedded images
|
||||||
|
- HTML and text templates
|
||||||
|
- Automatic encoding of special characters
|
||||||
|
- SSL and TLS
|
||||||
|
- Sending multiple emails with the same SMTP connection
|
||||||
|
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
https://godoc.org/github.com/go-mail/mail
|
||||||
|
|
||||||
|
|
||||||
|
## Download
|
||||||
|
|
||||||
|
If you're already using a dependency manager, like [dep][dep], use the following
|
||||||
|
import path:
|
||||||
|
|
||||||
|
```
|
||||||
|
github.com/go-mail/mail
|
||||||
|
```
|
||||||
|
|
||||||
|
If you *aren't* using vendoring, `go get` the [Gopkg.in](http://gopkg.in)
|
||||||
|
import path:
|
||||||
|
|
||||||
|
```
|
||||||
|
gopkg.in/mail.v2
|
||||||
|
```
|
||||||
|
|
||||||
|
[dep]: https://github.com/golang/dep#readme
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
See the [examples in the documentation](https://godoc.org/github.com/go-mail/mail#example-package).
|
||||||
|
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### x509: certificate signed by unknown authority
|
||||||
|
|
||||||
|
If you get this error it means the certificate used by the SMTP server is not
|
||||||
|
considered valid by the client running Gomail. As a quick workaround you can
|
||||||
|
bypass the verification of the server's certificate chain and host name by using
|
||||||
|
`SetTLSConfig`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
|
"gopkg.in/mail.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
d := mail.NewDialer("smtp.example.com", 587, "user", "123456")
|
||||||
|
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
|
||||||
|
// Send emails using d.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, however, that this is insecure and should not be used in production.
|
||||||
|
|
||||||
|
### Transitioning Existing Codebases
|
||||||
|
|
||||||
|
If you're already using the original Gomail, switching is as easy as updating
|
||||||
|
the import line to:
|
||||||
|
|
||||||
|
```
|
||||||
|
import gomail "gopkg.in/mail.v2"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
Contributions are more than welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for
|
||||||
|
more info.
|
||||||
|
|
||||||
|
|
||||||
|
## Change log
|
||||||
|
|
||||||
|
See [CHANGELOG.md](CHANGELOG.md).
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
|
||||||
|
## Support & Contact
|
||||||
|
|
||||||
|
You can ask questions on the [Gomail
|
||||||
|
thread](https://groups.google.com/d/topic/golang-nuts/jMxZHzvvEVg/discussion)
|
||||||
|
in the Go mailing-list.
|
||||||
49
vendor/gopkg.in/mail.v2/auth.go
сгенерированный
поставляемый
Обычный файл
49
vendor/gopkg.in/mail.v2/auth.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,49 @@
|
|||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/smtp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// loginAuth is an smtp.Auth that implements the LOGIN authentication mechanism.
|
||||||
|
type loginAuth struct {
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
host string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
||||||
|
if !server.TLS {
|
||||||
|
advertised := false
|
||||||
|
for _, mechanism := range server.Auth {
|
||||||
|
if mechanism == "LOGIN" {
|
||||||
|
advertised = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !advertised {
|
||||||
|
return "", nil, errors.New("gomail: unencrypted connection")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if server.Name != a.host {
|
||||||
|
return "", nil, errors.New("gomail: wrong host name")
|
||||||
|
}
|
||||||
|
return "LOGIN", nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||||
|
if !more {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case bytes.Equal(fromServer, []byte("Username:")):
|
||||||
|
return []byte(a.username), nil
|
||||||
|
case bytes.Equal(fromServer, []byte("Password:")):
|
||||||
|
return []byte(a.password), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("gomail: unexpected server challenge: %s", fromServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
5
vendor/gopkg.in/gomail.v2/doc.go → vendor/gopkg.in/mail.v2/doc.go
сгенерированный
поставляемый
5
vendor/gopkg.in/gomail.v2/doc.go → vendor/gopkg.in/mail.v2/doc.go
сгенерированный
поставляемый
@@ -1,5 +1,6 @@
|
|||||||
// Package gomail provides a simple interface to compose emails and to mail them
|
// Package gomail provides a simple interface to compose emails and to mail them
|
||||||
// efficiently.
|
// efficiently.
|
||||||
//
|
//
|
||||||
// More info on Github: https://github.com/go-gomail/gomail
|
// More info on Github: https://github.com/go-mail/mail
|
||||||
package gomail
|
//
|
||||||
|
package mail
|
||||||
16
vendor/gopkg.in/mail.v2/errors.go
сгенерированный
поставляемый
Обычный файл
16
vendor/gopkg.in/mail.v2/errors.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,16 @@
|
|||||||
|
package mail
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// A SendError represents the failure to transmit a Message, detailing the cause
|
||||||
|
// of the failure and index of the Message within a batch.
|
||||||
|
type SendError struct {
|
||||||
|
// Index specifies the index of the Message within a batch.
|
||||||
|
Index uint
|
||||||
|
Cause error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *SendError) Error() string {
|
||||||
|
return fmt.Sprintf("gomail: could not send email %d: %v",
|
||||||
|
err.Index+1, err.Cause)
|
||||||
|
}
|
||||||
159
vendor/gopkg.in/gomail.v2/message.go → vendor/gopkg.in/mail.v2/message.go
сгенерированный
поставляемый
159
vendor/gopkg.in/gomail.v2/message.go → vendor/gopkg.in/mail.v2/message.go
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
|||||||
package gomail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -11,20 +11,22 @@ import (
|
|||||||
// Message represents an email.
|
// Message represents an email.
|
||||||
type Message struct {
|
type Message struct {
|
||||||
header header
|
header header
|
||||||
parts []part
|
parts []*part
|
||||||
attachments []*file
|
attachments []*file
|
||||||
embedded []*file
|
embedded []*file
|
||||||
charset string
|
charset string
|
||||||
encoding Encoding
|
encoding Encoding
|
||||||
hEncoder mimeEncoder
|
hEncoder mimeEncoder
|
||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
|
boundary string
|
||||||
}
|
}
|
||||||
|
|
||||||
type header map[string][]string
|
type header map[string][]string
|
||||||
|
|
||||||
type part struct {
|
type part struct {
|
||||||
header header
|
contentType string
|
||||||
copier func(io.Writer) error
|
copier func(io.Writer) error
|
||||||
|
encoding Encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMessage creates a new message. It uses UTF-8 and quoted-printable encoding
|
// NewMessage creates a new message. It uses UTF-8 and quoted-printable encoding
|
||||||
@@ -96,6 +98,11 @@ const (
|
|||||||
Unencoded Encoding = "8bit"
|
Unencoded Encoding = "8bit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SetBoundary sets a custom multipart boundary.
|
||||||
|
func (m *Message) SetBoundary(boundary string) {
|
||||||
|
m.boundary = boundary
|
||||||
|
}
|
||||||
|
|
||||||
// SetHeader sets a value to the given header field.
|
// SetHeader sets a value to the given header field.
|
||||||
func (m *Message) SetHeader(field string, value ...string) {
|
func (m *Message) SetHeader(field string, value ...string) {
|
||||||
m.encodeHeader(value)
|
m.encodeHeader(value)
|
||||||
@@ -126,6 +133,10 @@ func (m *Message) SetAddressHeader(field, address, name string) {
|
|||||||
|
|
||||||
// FormatAddress formats an address and a name as a valid RFC 5322 address.
|
// FormatAddress formats an address and a name as a valid RFC 5322 address.
|
||||||
func (m *Message) FormatAddress(address, name string) string {
|
func (m *Message) FormatAddress(address, name string) string {
|
||||||
|
if name == "" {
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
enc := m.encodeString(name)
|
enc := m.encodeString(name)
|
||||||
if enc == name {
|
if enc == name {
|
||||||
m.buf.WriteByte('"')
|
m.buf.WriteByte('"')
|
||||||
@@ -177,53 +188,66 @@ func (m *Message) GetHeader(field string) []string {
|
|||||||
return m.header[field]
|
return m.header[field]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBody sets the body of the message.
|
// SetBody sets the body of the message. It replaces any content previously set
|
||||||
func (m *Message) SetBody(contentType, body string) {
|
// by SetBody, SetBodyWriter, AddAlternative or AddAlternativeWriter.
|
||||||
m.parts = []part{
|
func (m *Message) SetBody(contentType, body string, settings ...PartSetting) {
|
||||||
{
|
m.SetBodyWriter(contentType, newCopier(body), settings...)
|
||||||
header: m.getPartHeader(contentType),
|
}
|
||||||
copier: func(w io.Writer) error {
|
|
||||||
_, err := io.WriteString(w, body)
|
// SetBodyWriter sets the body of the message. It can be useful with the
|
||||||
return err
|
// text/template or html/template packages.
|
||||||
},
|
func (m *Message) SetBodyWriter(contentType string, f func(io.Writer) error, settings ...PartSetting) {
|
||||||
},
|
m.parts = []*part{m.newPart(contentType, f, settings)}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAlternative adds an alternative part to the message.
|
// AddAlternative adds an alternative part to the message.
|
||||||
//
|
//
|
||||||
// It is commonly used to send HTML emails that default to the plain text
|
// It is commonly used to send HTML emails that default to the plain text
|
||||||
// version for backward compatibility.
|
// version for backward compatibility. AddAlternative appends the new part to
|
||||||
//
|
// the end of the message. So the plain text part should be added before the
|
||||||
// More info: http://en.wikipedia.org/wiki/MIME#Alternative
|
// HTML part. See http://en.wikipedia.org/wiki/MIME#Alternative
|
||||||
func (m *Message) AddAlternative(contentType, body string) {
|
func (m *Message) AddAlternative(contentType, body string, settings ...PartSetting) {
|
||||||
m.parts = append(m.parts,
|
m.AddAlternativeWriter(contentType, newCopier(body), settings...)
|
||||||
part{
|
}
|
||||||
header: m.getPartHeader(contentType),
|
|
||||||
copier: func(w io.Writer) error {
|
func newCopier(s string) func(io.Writer) error {
|
||||||
_, err := io.WriteString(w, body)
|
return func(w io.Writer) error {
|
||||||
return err
|
_, err := io.WriteString(w, s)
|
||||||
},
|
return err
|
||||||
},
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAlternativeWriter adds an alternative part to the message. It can be
|
// AddAlternativeWriter adds an alternative part to the message. It can be
|
||||||
// useful with the text/template or html/template packages.
|
// useful with the text/template or html/template packages.
|
||||||
func (m *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error) {
|
func (m *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error, settings ...PartSetting) {
|
||||||
m.parts = []part{
|
m.parts = append(m.parts, m.newPart(contentType, f, settings))
|
||||||
{
|
|
||||||
header: m.getPartHeader(contentType),
|
|
||||||
copier: f,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) getPartHeader(contentType string) header {
|
func (m *Message) newPart(contentType string, f func(io.Writer) error, settings []PartSetting) *part {
|
||||||
return map[string][]string{
|
p := &part{
|
||||||
"Content-Type": {contentType + "; charset=" + m.charset},
|
contentType: contentType,
|
||||||
"Content-Transfer-Encoding": {string(m.encoding)},
|
copier: f,
|
||||||
|
encoding: m.encoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, s := range settings {
|
||||||
|
s(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// A PartSetting can be used as an argument in Message.SetBody,
|
||||||
|
// Message.SetBodyWriter, Message.AddAlternative or Message.AddAlternativeWriter
|
||||||
|
// to configure the part added to a message.
|
||||||
|
type PartSetting func(*part)
|
||||||
|
|
||||||
|
// SetPartEncoding sets the encoding of the part added to the message. By
|
||||||
|
// default, parts use the same encoding than the message.
|
||||||
|
func SetPartEncoding(e Encoding) PartSetting {
|
||||||
|
return PartSetting(func(p *part) {
|
||||||
|
p.encoding = e
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type file struct {
|
type file struct {
|
||||||
@@ -252,6 +276,14 @@ func SetHeader(h map[string][]string) FileSetting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename is a file setting to set the name of the attachment if the name is
|
||||||
|
// different than the filename on disk.
|
||||||
|
func Rename(name string) FileSetting {
|
||||||
|
return func(f *file) {
|
||||||
|
f.Name = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetCopyFunc is a file setting to replace the function that runs when the
|
// SetCopyFunc is a file setting to replace the function that runs when the
|
||||||
// message is sent. It should copy the content of the file to the io.Writer.
|
// message is sent. It should copy the content of the file to the io.Writer.
|
||||||
//
|
//
|
||||||
@@ -263,8 +295,28 @@ func SetCopyFunc(f func(io.Writer) error) FileSetting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) appendFile(list []*file, name string, settings []FileSetting) []*file {
|
// AttachReader attaches a file using an io.Reader
|
||||||
f := &file{
|
func (m *Message) AttachReader(name string, r io.Reader, settings ...FileSetting) {
|
||||||
|
m.attachments = m.appendFile(m.attachments, fileFromReader(name, r), settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach attaches the files to the email.
|
||||||
|
func (m *Message) Attach(filename string, settings ...FileSetting) {
|
||||||
|
m.attachments = m.appendFile(m.attachments, fileFromFilename(filename), settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbedReader embeds the images to the email.
|
||||||
|
func (m *Message) EmbedReader(name string, r io.Reader, settings ...FileSetting) {
|
||||||
|
m.embedded = m.appendFile(m.embedded, fileFromReader(name, r), settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embed embeds the images to the email.
|
||||||
|
func (m *Message) Embed(filename string, settings ...FileSetting) {
|
||||||
|
m.embedded = m.appendFile(m.embedded, fileFromFilename(filename), settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileFromFilename(name string) *file {
|
||||||
|
return &file{
|
||||||
Name: filepath.Base(name),
|
Name: filepath.Base(name),
|
||||||
Header: make(map[string][]string),
|
Header: make(map[string][]string),
|
||||||
CopyFunc: func(w io.Writer) error {
|
CopyFunc: func(w io.Writer) error {
|
||||||
@@ -279,7 +331,22 @@ func (m *Message) appendFile(list []*file, name string, settings []FileSetting)
|
|||||||
return h.Close()
|
return h.Close()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileFromReader(name string, r io.Reader) *file {
|
||||||
|
return &file{
|
||||||
|
Name: filepath.Base(name),
|
||||||
|
Header: make(map[string][]string),
|
||||||
|
CopyFunc: func(w io.Writer) error {
|
||||||
|
if _, err := io.Copy(w, r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Message) appendFile(list []*file, f *file, settings []FileSetting) []*file {
|
||||||
for _, s := range settings {
|
for _, s := range settings {
|
||||||
s(f)
|
s(f)
|
||||||
}
|
}
|
||||||
@@ -290,13 +357,3 @@ func (m *Message) appendFile(list []*file, name string, settings []FileSetting)
|
|||||||
|
|
||||||
return append(list, f)
|
return append(list, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach attaches the files to the email.
|
|
||||||
func (m *Message) Attach(filename string, settings ...FileSetting) {
|
|
||||||
m.attachments = m.appendFile(m.attachments, filename, settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Embed embeds the images to the email.
|
|
||||||
func (m *Message) Embed(filename string, settings ...FileSetting) {
|
|
||||||
m.embedded = m.appendFile(m.embedded, filename, settings)
|
|
||||||
}
|
|
||||||
8
vendor/gopkg.in/gomail.v2/mime.go → vendor/gopkg.in/mail.v2/mime.go
сгенерированный
поставляемый
8
vendor/gopkg.in/gomail.v2/mime.go → vendor/gopkg.in/mail.v2/mime.go
сгенерированный
поставляемый
@@ -1,10 +1,11 @@
|
|||||||
// +build go1.5
|
// +build go1.5
|
||||||
|
|
||||||
package gomail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mime"
|
"mime"
|
||||||
"mime/quotedprintable"
|
"mime/quotedprintable"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var newQPWriter = quotedprintable.NewWriter
|
var newQPWriter = quotedprintable.NewWriter
|
||||||
@@ -14,6 +15,7 @@ type mimeEncoder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bEncoding = mimeEncoder{mime.BEncoding}
|
bEncoding = mimeEncoder{mime.BEncoding}
|
||||||
qEncoding = mimeEncoder{mime.QEncoding}
|
qEncoding = mimeEncoder{mime.QEncoding}
|
||||||
|
lastIndexByte = strings.LastIndexByte
|
||||||
)
|
)
|
||||||
25
vendor/gopkg.in/mail.v2/mime_go14.go
сгенерированный
поставляемый
Обычный файл
25
vendor/gopkg.in/mail.v2/mime_go14.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,25 @@
|
|||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package mail
|
||||||
|
|
||||||
|
import "gopkg.in/alexcesaro/quotedprintable.v3"
|
||||||
|
|
||||||
|
var newQPWriter = quotedprintable.NewWriter
|
||||||
|
|
||||||
|
type mimeEncoder struct {
|
||||||
|
quotedprintable.WordEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
bEncoding = mimeEncoder{quotedprintable.BEncoding}
|
||||||
|
qEncoding = mimeEncoder{quotedprintable.QEncoding}
|
||||||
|
lastIndexByte = func(s string, c byte) int {
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
|
||||||
|
if s[i] == c {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
)
|
||||||
17
vendor/gopkg.in/gomail.v2/send.go → vendor/gopkg.in/mail.v2/send.go
сгенерированный
поставляемый
17
vendor/gopkg.in/gomail.v2/send.go → vendor/gopkg.in/mail.v2/send.go
сгенерированный
поставляемый
@@ -1,10 +1,10 @@
|
|||||||
package gomail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/mail"
|
stdmail "net/mail"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sender is the interface that wraps the Send method.
|
// Sender is the interface that wraps the Send method.
|
||||||
@@ -20,7 +20,7 @@ type SendCloser interface {
|
|||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SendFunc is a function that sends emails to the given adresses.
|
// A SendFunc is a function that sends emails to the given addresses.
|
||||||
//
|
//
|
||||||
// The SendFunc type is an adapter to allow the use of ordinary functions as
|
// The SendFunc type is an adapter to allow the use of ordinary functions as
|
||||||
// email senders. If f is a function with the appropriate signature, SendFunc(f)
|
// email senders. If f is a function with the appropriate signature, SendFunc(f)
|
||||||
@@ -36,7 +36,7 @@ func (f SendFunc) Send(from string, to []string, msg io.WriterTo) error {
|
|||||||
func Send(s Sender, msg ...*Message) error {
|
func Send(s Sender, msg ...*Message) error {
|
||||||
for i, m := range msg {
|
for i, m := range msg {
|
||||||
if err := send(s, m); err != nil {
|
if err := send(s, m); err != nil {
|
||||||
return fmt.Errorf("gomail: could not send email %d: %v", i+1, err)
|
return &SendError{Cause: err, Index: uint(i)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,10 +108,9 @@ func addAddress(list []string, addr string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseAddress(field string) (string, error) {
|
func parseAddress(field string) (string, error) {
|
||||||
a, err := mail.ParseAddress(field)
|
addr, err := stdmail.ParseAddress(field)
|
||||||
if a == nil {
|
if err != nil {
|
||||||
return "", err
|
return "", fmt.Errorf("gomail: invalid address %q: %v", field, err)
|
||||||
}
|
}
|
||||||
|
return addr.Address, nil
|
||||||
return a.Address, err
|
|
||||||
}
|
}
|
||||||
292
vendor/gopkg.in/mail.v2/smtp.go
сгенерированный
поставляемый
Обычный файл
292
vendor/gopkg.in/mail.v2/smtp.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,292 @@
|
|||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/smtp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Dialer is a dialer to an SMTP server.
|
||||||
|
type Dialer struct {
|
||||||
|
// Host represents the host of the SMTP server.
|
||||||
|
Host string
|
||||||
|
// Port represents the port of the SMTP server.
|
||||||
|
Port int
|
||||||
|
// Username is the username to use to authenticate to the SMTP server.
|
||||||
|
Username string
|
||||||
|
// Password is the password to use to authenticate to the SMTP server.
|
||||||
|
Password string
|
||||||
|
// Auth represents the authentication mechanism used to authenticate to the
|
||||||
|
// SMTP server.
|
||||||
|
Auth smtp.Auth
|
||||||
|
// SSL defines whether an SSL connection is used. It should be false in
|
||||||
|
// most cases since the authentication mechanism should use the STARTTLS
|
||||||
|
// extension instead.
|
||||||
|
SSL bool
|
||||||
|
// TLSConfig represents the TLS configuration used for the TLS (when the
|
||||||
|
// STARTTLS extension is used) or SSL connection.
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
// StartTLSPolicy represents the TLS security level required to
|
||||||
|
// communicate with the SMTP server.
|
||||||
|
//
|
||||||
|
// This defaults to OpportunisticStartTLS for backwards compatibility,
|
||||||
|
// but we recommend MandatoryStartTLS for all modern SMTP servers.
|
||||||
|
//
|
||||||
|
// This option has no effect if SSL is set to true.
|
||||||
|
StartTLSPolicy StartTLSPolicy
|
||||||
|
// LocalName is the hostname sent to the SMTP server with the HELO command.
|
||||||
|
// By default, "localhost" is sent.
|
||||||
|
LocalName string
|
||||||
|
// Timeout to use for read/write operations. Defaults to 10 seconds, can
|
||||||
|
// be set to 0 to disable timeouts.
|
||||||
|
Timeout time.Duration
|
||||||
|
// Whether we should retry mailing if the connection returned an error,
|
||||||
|
// defaults to true.
|
||||||
|
RetryFailure bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDialer returns a new SMTP Dialer. The given parameters are used to connect
|
||||||
|
// to the SMTP server.
|
||||||
|
func NewDialer(host string, port int, username, password string) *Dialer {
|
||||||
|
return &Dialer{
|
||||||
|
Host: host,
|
||||||
|
Port: port,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
SSL: port == 465,
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
RetryFailure: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPlainDialer returns a new SMTP Dialer. The given parameters are used to
|
||||||
|
// connect to the SMTP server.
|
||||||
|
//
|
||||||
|
// Deprecated: Use NewDialer instead.
|
||||||
|
func NewPlainDialer(host string, port int, username, password string) *Dialer {
|
||||||
|
return NewDialer(host, port, username, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetDialTimeout specifies the DialTimeout function to establish a connection
|
||||||
|
// to the SMTP server. This can be used to override dialing in the case that a
|
||||||
|
// proxy or other special behavior is needed.
|
||||||
|
var NetDialTimeout = net.DialTimeout
|
||||||
|
|
||||||
|
// Dial dials and authenticates to an SMTP server. The returned SendCloser
|
||||||
|
// should be closed when done using it.
|
||||||
|
func (d *Dialer) Dial() (SendCloser, error) {
|
||||||
|
conn, err := NetDialTimeout("tcp", addr(d.Host, d.Port), d.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.SSL {
|
||||||
|
conn = tlsClient(conn, d.tlsConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := smtpNewClient(conn, d.Host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Timeout > 0 {
|
||||||
|
conn.SetDeadline(time.Now().Add(d.Timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.LocalName != "" {
|
||||||
|
if err := c.Hello(d.LocalName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !d.SSL && d.StartTLSPolicy != NoStartTLS {
|
||||||
|
ok, _ := c.Extension("STARTTLS")
|
||||||
|
if !ok && d.StartTLSPolicy == MandatoryStartTLS {
|
||||||
|
err := StartTLSUnsupportedError{
|
||||||
|
Policy: d.StartTLSPolicy}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
if err := c.StartTLS(d.tlsConfig()); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Auth == nil && d.Username != "" {
|
||||||
|
if ok, auths := c.Extension("AUTH"); ok {
|
||||||
|
if strings.Contains(auths, "CRAM-MD5") {
|
||||||
|
d.Auth = smtp.CRAMMD5Auth(d.Username, d.Password)
|
||||||
|
} else if strings.Contains(auths, "LOGIN") &&
|
||||||
|
!strings.Contains(auths, "PLAIN") {
|
||||||
|
d.Auth = &loginAuth{
|
||||||
|
username: d.Username,
|
||||||
|
password: d.Password,
|
||||||
|
host: d.Host,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.Auth = smtp.PlainAuth("", d.Username, d.Password, d.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Auth != nil {
|
||||||
|
if err = c.Auth(d.Auth); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &smtpSender{c, conn, d}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialer) tlsConfig() *tls.Config {
|
||||||
|
if d.TLSConfig == nil {
|
||||||
|
return &tls.Config{ServerName: d.Host}
|
||||||
|
}
|
||||||
|
return d.TLSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTLSPolicy constants are valid values for Dialer.StartTLSPolicy.
|
||||||
|
type StartTLSPolicy int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// OpportunisticStartTLS means that SMTP transactions are encrypted if
|
||||||
|
// STARTTLS is supported by the SMTP server. Otherwise, messages are
|
||||||
|
// sent in the clear. This is the default setting.
|
||||||
|
OpportunisticStartTLS StartTLSPolicy = iota
|
||||||
|
// MandatoryStartTLS means that SMTP transactions must be encrypted.
|
||||||
|
// SMTP transactions are aborted unless STARTTLS is supported by the
|
||||||
|
// SMTP server.
|
||||||
|
MandatoryStartTLS
|
||||||
|
// NoStartTLS means encryption is disabled and messages are sent in the
|
||||||
|
// clear.
|
||||||
|
NoStartTLS = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
func (policy *StartTLSPolicy) String() string {
|
||||||
|
switch *policy {
|
||||||
|
case OpportunisticStartTLS:
|
||||||
|
return "OpportunisticStartTLS"
|
||||||
|
case MandatoryStartTLS:
|
||||||
|
return "MandatoryStartTLS"
|
||||||
|
case NoStartTLS:
|
||||||
|
return "NoStartTLS"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("StartTLSPolicy:%v", *policy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTLSUnsupportedError is returned by Dial when connecting to an SMTP
|
||||||
|
// server that does not support STARTTLS.
|
||||||
|
type StartTLSUnsupportedError struct {
|
||||||
|
Policy StartTLSPolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e StartTLSUnsupportedError) Error() string {
|
||||||
|
return "gomail: " + e.Policy.String() + " required, but " +
|
||||||
|
"SMTP server does not support STARTTLS"
|
||||||
|
}
|
||||||
|
|
||||||
|
func addr(host string, port int) string {
|
||||||
|
return fmt.Sprintf("%s:%d", host, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialAndSend opens a connection to the SMTP server, sends the given emails and
|
||||||
|
// closes the connection.
|
||||||
|
func (d *Dialer) DialAndSend(m ...*Message) error {
|
||||||
|
s, err := d.Dial()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
return Send(s, m...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type smtpSender struct {
|
||||||
|
smtpClient
|
||||||
|
conn net.Conn
|
||||||
|
d *Dialer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *smtpSender) retryError(err error) bool {
|
||||||
|
if !c.d.RetryFailure {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return err == io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||||
|
if c.d.Timeout > 0 {
|
||||||
|
c.conn.SetDeadline(time.Now().Add(c.d.Timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Mail(from); err != nil {
|
||||||
|
if c.retryError(err) {
|
||||||
|
// This is probably due to a timeout, so reconnect and try again.
|
||||||
|
sc, derr := c.d.Dial()
|
||||||
|
if derr == nil {
|
||||||
|
if s, ok := sc.(*smtpSender); ok {
|
||||||
|
*c = *s
|
||||||
|
return c.Send(from, to, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range to {
|
||||||
|
if err := c.Rcpt(addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := c.Data()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = msg.WriteTo(w); err != nil {
|
||||||
|
w.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *smtpSender) Close() error {
|
||||||
|
return c.Quit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stubbed out for tests.
|
||||||
|
var (
|
||||||
|
tlsClient = tls.Client
|
||||||
|
smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) {
|
||||||
|
return smtp.NewClient(conn, host)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type smtpClient interface {
|
||||||
|
Hello(string) error
|
||||||
|
Extension(string) (bool, string)
|
||||||
|
StartTLS(*tls.Config) error
|
||||||
|
Auth(smtp.Auth) error
|
||||||
|
Mail(string) error
|
||||||
|
Rcpt(string) error
|
||||||
|
Data() (io.WriteCloser, error)
|
||||||
|
Quit() error
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
121
vendor/gopkg.in/gomail.v2/writeto.go → vendor/gopkg.in/mail.v2/writeto.go
сгенерированный
поставляемый
121
vendor/gopkg.in/gomail.v2/writeto.go → vendor/gopkg.in/mail.v2/writeto.go
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
|||||||
package gomail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"mime"
|
"mime"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,8 +19,8 @@ func (m *Message) WriteTo(w io.Writer) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *messageWriter) writeMessage(m *Message) {
|
func (w *messageWriter) writeMessage(m *Message) {
|
||||||
if _, ok := m.header["Mime-Version"]; !ok {
|
if _, ok := m.header["MIME-Version"]; !ok {
|
||||||
w.writeString("Mime-Version: 1.0\r\n")
|
w.writeString("MIME-Version: 1.0\r\n")
|
||||||
}
|
}
|
||||||
if _, ok := m.header["Date"]; !ok {
|
if _, ok := m.header["Date"]; !ok {
|
||||||
w.writeHeader("Date", m.FormatDate(now()))
|
w.writeHeader("Date", m.FormatDate(now()))
|
||||||
@@ -27,19 +28,18 @@ func (w *messageWriter) writeMessage(m *Message) {
|
|||||||
w.writeHeaders(m.header)
|
w.writeHeaders(m.header)
|
||||||
|
|
||||||
if m.hasMixedPart() {
|
if m.hasMixedPart() {
|
||||||
w.openMultipart("mixed")
|
w.openMultipart("mixed", m.boundary)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.hasRelatedPart() {
|
if m.hasRelatedPart() {
|
||||||
w.openMultipart("related")
|
w.openMultipart("related", m.boundary)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.hasAlternativePart() {
|
if m.hasAlternativePart() {
|
||||||
w.openMultipart("alternative")
|
w.openMultipart("alternative", m.boundary)
|
||||||
}
|
}
|
||||||
for _, part := range m.parts {
|
for _, part := range m.parts {
|
||||||
w.writeHeaders(part.header)
|
w.writePart(part, m.charset)
|
||||||
w.writeBody(part.copier, m.encoding)
|
|
||||||
}
|
}
|
||||||
if m.hasAlternativePart() {
|
if m.hasAlternativePart() {
|
||||||
w.closeMultipart()
|
w.closeMultipart()
|
||||||
@@ -77,9 +77,12 @@ type messageWriter struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *messageWriter) openMultipart(mimeType string) {
|
func (w *messageWriter) openMultipart(mimeType, boundary string) {
|
||||||
mw := multipart.NewWriter(w)
|
mw := multipart.NewWriter(w)
|
||||||
contentType := "multipart/" + mimeType + "; boundary=" + mw.Boundary()
|
if boundary != "" {
|
||||||
|
mw.SetBoundary(boundary)
|
||||||
|
}
|
||||||
|
contentType := "multipart/" + mimeType + ";\r\n boundary=" + mw.Boundary()
|
||||||
w.writers[w.depth] = mw
|
w.writers[w.depth] = mw
|
||||||
|
|
||||||
if w.depth == 0 {
|
if w.depth == 0 {
|
||||||
@@ -104,6 +107,14 @@ func (w *messageWriter) closeMultipart() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *messageWriter) writePart(p *part, charset string) {
|
||||||
|
w.writeHeaders(map[string][]string{
|
||||||
|
"Content-Type": {p.contentType + "; charset=" + charset},
|
||||||
|
"Content-Transfer-Encoding": {string(p.encoding)},
|
||||||
|
})
|
||||||
|
w.writeBody(p.copier, p.encoding)
|
||||||
|
}
|
||||||
|
|
||||||
func (w *messageWriter) addFiles(files []*file, isAttachment bool) {
|
func (w *messageWriter) addFiles(files []*file, isAttachment bool) {
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
if _, ok := f.Header["Content-Type"]; !ok {
|
if _, ok := f.Header["Content-Type"]; !ok {
|
||||||
@@ -150,30 +161,90 @@ func (w *messageWriter) Write(p []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *messageWriter) writeString(s string) {
|
func (w *messageWriter) writeString(s string) {
|
||||||
n, _ := io.WriteString(w.w, s)
|
if w.err != nil { // do nothing when in error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var n int
|
||||||
|
n, w.err = io.WriteString(w.w, s)
|
||||||
w.n += int64(n)
|
w.n += int64(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *messageWriter) writeStrings(a []string, sep string) {
|
|
||||||
if len(a) > 0 {
|
|
||||||
w.writeString(a[0])
|
|
||||||
if len(a) == 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, s := range a[1:] {
|
|
||||||
w.writeString(sep)
|
|
||||||
w.writeString(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *messageWriter) writeHeader(k string, v ...string) {
|
func (w *messageWriter) writeHeader(k string, v ...string) {
|
||||||
w.writeString(k)
|
w.writeString(k)
|
||||||
|
if len(v) == 0 {
|
||||||
|
w.writeString(":\r\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
w.writeString(": ")
|
w.writeString(": ")
|
||||||
w.writeStrings(v, ", ")
|
|
||||||
|
// Max header line length is 78 characters in RFC 5322 and 76 characters
|
||||||
|
// in RFC 2047. So for the sake of simplicity we use the 76 characters
|
||||||
|
// limit.
|
||||||
|
charsLeft := 76 - len(k) - len(": ")
|
||||||
|
|
||||||
|
for i, s := range v {
|
||||||
|
// If the line is already too long, insert a newline right away.
|
||||||
|
if charsLeft < 1 {
|
||||||
|
if i == 0 {
|
||||||
|
w.writeString("\r\n ")
|
||||||
|
} else {
|
||||||
|
w.writeString(",\r\n ")
|
||||||
|
}
|
||||||
|
charsLeft = 75
|
||||||
|
} else if i != 0 {
|
||||||
|
w.writeString(", ")
|
||||||
|
charsLeft -= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// While the header content is too long, fold it by inserting a newline.
|
||||||
|
for len(s) > charsLeft {
|
||||||
|
s = w.writeLine(s, charsLeft)
|
||||||
|
charsLeft = 75
|
||||||
|
}
|
||||||
|
w.writeString(s)
|
||||||
|
if i := lastIndexByte(s, '\n'); i != -1 {
|
||||||
|
charsLeft = 75 - (len(s) - i - 1)
|
||||||
|
} else {
|
||||||
|
charsLeft -= len(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
w.writeString("\r\n")
|
w.writeString("\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *messageWriter) writeLine(s string, charsLeft int) string {
|
||||||
|
// If there is already a newline before the limit. Write the line.
|
||||||
|
if i := strings.IndexByte(s, '\n'); i != -1 && i < charsLeft {
|
||||||
|
w.writeString(s[:i+1])
|
||||||
|
return s[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := charsLeft - 1; i >= 0; i-- {
|
||||||
|
if s[i] == ' ' {
|
||||||
|
w.writeString(s[:i])
|
||||||
|
w.writeString("\r\n ")
|
||||||
|
return s[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could not insert a newline cleanly so look for a space or a newline
|
||||||
|
// even if it is after the limit.
|
||||||
|
for i := 75; i < len(s); i++ {
|
||||||
|
if s[i] == ' ' {
|
||||||
|
w.writeString(s[:i])
|
||||||
|
w.writeString("\r\n ")
|
||||||
|
return s[i+1:]
|
||||||
|
}
|
||||||
|
if s[i] == '\n' {
|
||||||
|
w.writeString(s[:i+1])
|
||||||
|
return s[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too bad, no space or newline in the whole string. Just write everything.
|
||||||
|
w.writeString(s)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (w *messageWriter) writeHeaders(h map[string][]string) {
|
func (w *messageWriter) writeHeaders(h map[string][]string) {
|
||||||
if w.depth == 0 {
|
if w.depth == 0 {
|
||||||
for k, v := range h {
|
for k, v := range h {
|
||||||
Ссылка в новой задаче
Block a user