Merge pull request #57 from glaszig/starttls

allow disabling starttls
This commit is contained in:
Michael de Wit 2021-10-31 14:36:27 +01:00 committed by GitHub
commit c75190e21a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 456 additions and 167 deletions

20
DOCS.md
View file

@ -10,6 +10,7 @@ You can configure the plugin using the following parameters:
* **username** - SMTP username
* **password** - SMTP password
* **skip_verify** - Skip verification of SSL certificates, defaults to `false`
* **starttls** - Enable/Disable STARTTLS
* **recipients** - List of recipients to send this mail to (besides the commit author)
* **recipients_file** - Filename to load additional recipients from (textfile with one email per line) (besides the commit author)
* **recipients_only** - Do not send mails to the commit author, but only to **recipients**, defaults to `false`
@ -127,3 +128,22 @@ steps:
password: 12345
+ skip_verify: true
```
### STARTTLS
By default, STARTTLS is being used opportunistically meaning, if advertised
by the server, traffic is going to be encrypted.
You may want to disable STARTTLS, e.g., with faulty and/or internal servers:
```diff
steps:
- name: notify
image: drillster/drone-email
settings:
from: noreply@github.com
host: smtp.mailgun.org
username: octocat
password: 12345
+ starttls: false
```

View file

@ -66,6 +66,11 @@ func main() {
Usage: "skip tls verify",
EnvVar: "PLUGIN_SKIP_VERIFY",
},
cli.BoolFlag{
Name: "starttls",
Usage: "Enable/Disable STARTTLS",
EnvVar: "PLUGIN_STARTTLS",
},
cli.StringFlag{
Name: "recipients.file",
Usage: "file to read recipients from",
@ -407,6 +412,7 @@ func run(c *cli.Context) error {
Username: c.String("username"),
Password: c.String("password"),
SkipVerify: c.Bool("skip.verify"),
StartTLS: c.Bool("starttls"),
Recipients: c.StringSlice("recipients"),
RecipientsFile: c.String("recipients.file"),
RecipientsOnly: c.Bool("recipients.only"),

View file

@ -9,7 +9,7 @@ import (
"github.com/aymerick/douceur/inliner"
"github.com/drone/drone-go/template"
"github.com/jaytaylor/html2text"
"gopkg.in/gomail.v2"
gomail "gopkg.in/mail.v2"
)
type (
@ -88,6 +88,7 @@ type (
Username string
Password string
SkipVerify bool
StartTLS bool
Recipients []string
RecipientsFile string
RecipientsOnly bool
@ -147,9 +148,15 @@ func (p Plugin) Exec() error {
} else {
dialer = gomail.NewDialer(p.Config.Host, p.Config.Port, p.Config.Username, p.Config.Password)
}
if p.Config.SkipVerify {
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
if !p.Config.StartTLS {
dialer.StartTLSPolicy = gomail.NoStartTLS
}
dialer.LocalName = p.Config.ClientHostname
closer, err := dialer.Dial()

View file

@ -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.

92
vendor/gopkg.in/gomail.v2/README.md generated vendored
View file

@ -1,92 +0,0 @@
# Gomail
[![Build Status](https://travis-ci.org/go-gomail/gomail.svg?branch=v2)](https://travis-ci.org/go-gomail/gomail) [![Code Coverage](http://gocover.io/_badge/gopkg.in/gomail.v2)](http://gocover.io/gopkg.in/gomail.v2) [![Documentation](https://godoc.org/gopkg.in/gomail.v2?status.svg)](https://godoc.org/gopkg.in/gomail.v2)
## 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 is versioned using [gopkg.in](https://gopkg.in) so I promise
there 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
## 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`:
package main
import (
"crypto/tls"
"gopkg.in/gomail.v2"
)
func main() {
d := gomail.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.
## 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.

88
vendor/gopkg.in/mail.v2/CHANGELOG.md generated vendored Normal file
View file

@ -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.

129
vendor/gopkg.in/mail.v2/README.md generated vendored Normal file
View file

@ -0,0 +1,129 @@
# Gomail
[![Build Status](https://travis-ci.org/go-mail/mail.svg?branch=master)](https://travis-ci.org/go-mail/mail) [![Code Coverage](http://gocover.io/_badge/github.com/go-mail/mail)](http://gocover.io/github.com/go-mail/mail) [![Documentation](https://godoc.org/github.com/go-mail/mail?status.svg)](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.

View file

@ -1,4 +1,4 @@
package gomail
package mail
import (
"bytes"

View file

@ -1,5 +1,6 @@
// Package gomail provides a simple interface to compose emails and to mail them
// efficiently.
//
// More info on Github: https://github.com/go-gomail/gomail
package gomail
// More info on Github: https://github.com/go-mail/mail
//
package mail

16
vendor/gopkg.in/mail.v2/errors.go generated vendored Normal file
View file

@ -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)
}

View file

@ -1,4 +1,4 @@
package gomail
package mail
import (
"bytes"
@ -18,6 +18,7 @@ type Message struct {
encoding Encoding
hEncoder mimeEncoder
buf bytes.Buffer
boundary string
}
type header map[string][]string
@ -97,6 +98,11 @@ const (
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.
func (m *Message) SetHeader(field string, value ...string) {
m.encodeHeader(value)
@ -183,9 +189,15 @@ func (m *Message) GetHeader(field string) []string {
}
// SetBody sets the body of the message. It replaces any content previously set
// by SetBody, AddAlternative or AddAlternativeWriter.
// by SetBody, SetBodyWriter, AddAlternative or AddAlternativeWriter.
func (m *Message) SetBody(contentType, body string, settings ...PartSetting) {
m.parts = []*part{m.newPart(contentType, newCopier(body), settings)}
m.SetBodyWriter(contentType, newCopier(body), settings...)
}
// SetBodyWriter sets the body of the message. It can be useful with the
// 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.
@ -226,8 +238,8 @@ func (m *Message) newPart(contentType string, f func(io.Writer) error, settings
}
// A PartSetting can be used as an argument in Message.SetBody,
// Message.AddAlternative or Message.AddAlternativeWriter to configure the part
// added to a message.
// 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
@ -283,8 +295,28 @@ func SetCopyFunc(f func(io.Writer) error) FileSetting {
}
}
func (m *Message) appendFile(list []*file, name string, settings []FileSetting) []*file {
f := &file{
// AttachReader attaches a file using an io.Reader
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),
Header: make(map[string][]string),
CopyFunc: func(w io.Writer) error {
@ -299,7 +331,22 @@ func (m *Message) appendFile(list []*file, name string, settings []FileSetting)
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 {
s(f)
}
@ -310,13 +357,3 @@ func (m *Message) appendFile(list []*file, name string, settings []FileSetting)
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)
}

View file

@ -1,6 +1,6 @@
// +build go1.5
package gomail
package mail
import (
"mime"

View file

@ -1,6 +1,6 @@
// +build !go1.5
package gomail
package mail
import "gopkg.in/alexcesaro/quotedprintable.v3"

View file

@ -1,10 +1,10 @@
package gomail
package mail
import (
"errors"
"fmt"
"io"
"net/mail"
stdmail "net/mail"
)
// Sender is the interface that wraps the Send method.
@ -36,7 +36,7 @@ func (f SendFunc) Send(from string, to []string, msg io.WriterTo) error {
func Send(s Sender, msg ...*Message) error {
for i, m := range msg {
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,7 +108,7 @@ func addAddress(list []string, addr string) []string {
}
func parseAddress(field string) (string, error) {
addr, err := mail.ParseAddress(field)
addr, err := stdmail.ParseAddress(field)
if err != nil {
return "", fmt.Errorf("gomail: invalid address %q: %v", field, err)
}

View file

@ -1,4 +1,4 @@
package gomail
package mail
import (
"crypto/tls"
@ -27,23 +27,39 @@ type Dialer struct {
// 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
// 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,
Host: host,
Port: port,
Username: username,
Password: password,
SSL: port == 465,
Timeout: 10 * time.Second,
RetryFailure: true,
}
}
@ -55,10 +71,15 @@ 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), 10*time.Second)
conn, err := NetDialTimeout("tcp", addr(d.Host, d.Port), d.Timeout)
if err != nil {
return nil, err
}
@ -72,14 +93,25 @@ func (d *Dialer) Dial() (SendCloser, error) {
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 {
if ok, _ := c.Extension("STARTTLS"); ok {
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
@ -111,7 +143,7 @@ func (d *Dialer) Dial() (SendCloser, error) {
}
}
return &smtpSender{c, d}, nil
return &smtpSender{c, conn, d}, nil
}
func (d *Dialer) tlsConfig() *tls.Config {
@ -121,6 +153,47 @@ func (d *Dialer) tlsConfig() *tls.Config {
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)
}
@ -139,12 +212,29 @@ func (d *Dialer) DialAndSend(m ...*Message) error {
type smtpSender struct {
smtpClient
d *Dialer
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 err == io.EOF {
if c.retryError(err) {
// This is probably due to a timeout, so reconnect and try again.
sc, derr := c.d.Dial()
if derr == nil {
@ -154,6 +244,7 @@ func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
}
}
}
return err
}
@ -182,9 +273,8 @@ func (c *smtpSender) Close() error {
// Stubbed out for tests.
var (
netDialTimeout = net.DialTimeout
tlsClient = tls.Client
smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) {
tlsClient = tls.Client
smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) {
return smtp.NewClient(conn, host)
}
)

View file

@ -1,4 +1,4 @@
package gomail
package mail
import (
"encoding/base64"
@ -19,8 +19,8 @@ func (m *Message) WriteTo(w io.Writer) (int64, error) {
}
func (w *messageWriter) writeMessage(m *Message) {
if _, ok := m.header["Mime-Version"]; !ok {
w.writeString("Mime-Version: 1.0\r\n")
if _, ok := m.header["MIME-Version"]; !ok {
w.writeString("MIME-Version: 1.0\r\n")
}
if _, ok := m.header["Date"]; !ok {
w.writeHeader("Date", m.FormatDate(now()))
@ -28,15 +28,15 @@ func (w *messageWriter) writeMessage(m *Message) {
w.writeHeaders(m.header)
if m.hasMixedPart() {
w.openMultipart("mixed")
w.openMultipart("mixed", m.boundary)
}
if m.hasRelatedPart() {
w.openMultipart("related")
w.openMultipart("related", m.boundary)
}
if m.hasAlternativePart() {
w.openMultipart("alternative")
w.openMultipart("alternative", m.boundary)
}
for _, part := range m.parts {
w.writePart(part, m.charset)
@ -77,8 +77,11 @@ type messageWriter struct {
err error
}
func (w *messageWriter) openMultipart(mimeType string) {
func (w *messageWriter) openMultipart(mimeType, boundary string) {
mw := multipart.NewWriter(w)
if boundary != "" {
mw.SetBoundary(boundary)
}
contentType := "multipart/" + mimeType + ";\r\n boundary=" + mw.Boundary()
w.writers[w.depth] = mw
@ -158,7 +161,11 @@ func (w *messageWriter) Write(p []byte) (int, error) {
}
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)
}

8
vendor/vendor.json vendored
View file

@ -129,10 +129,10 @@
"revisionTime": "2015-07-16T17:19:45Z"
},
{
"checksumSHA1": "iq5WdjScmTU+LfNoerLuwcnXpdM=",
"path": "gopkg.in/gomail.v2",
"revision": "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1",
"revisionTime": "2016-04-11T21:29:32Z"
"checksumSHA1": "SoHkt4HLtGvg9wZIDX6BJTqkDgs=",
"path": "gopkg.in/mail.v2",
"revision": "f59b9b83a4e522098e3d3eb94e6f81850ad6e973",
"revisionTime": "2018-11-12T22:01:18Z"
},
{
"checksumSHA1": "12GqsW8PiRPnezDDy0v4brZrndM=",