mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-21 21:30:50 +01:00
Winni Neessen
d30a4a73c6
Introduce the QuickSend function for sending emails quickly with TLS and optional SMTP authentication. Added comprehensive unit tests to ensure QuickSend works correctly with different authentication mechanisms and handles various error scenarios.
112 lines
3.8 KiB
Go
112 lines
3.8 KiB
Go
// SPDX-FileCopyrightText: 2024 The go-mail Authors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package mail
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
)
|
|
|
|
type AuthData struct {
|
|
Auth bool
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
var testHookTLSConfig func() *tls.Config // nil, except for tests
|
|
|
|
// QuickSend is an all-in-one method for quickly sending simple text mails in go-mail.
|
|
//
|
|
// This method will create a new client that connects to the server at addr, switches to TLS if possible,
|
|
// authenticates with the optional AuthData provided in auth and create a new simple Msg with the provided
|
|
// subject string and message bytes as body. The message will be sent using from as sender address and will
|
|
// be delivered to every address in rcpts. QuickSend will always send as text/plain ContentType.
|
|
//
|
|
// For the SMTP authentication, if auth is not nil and AuthData.Auth is set to true, it will try to
|
|
// autodiscover the best SMTP authentication mechanism supported by the server. If auth is set to true
|
|
// but autodiscover is not able to find a suitable authentication mechanism or if the authentication
|
|
// fails, the mail delivery will fail completely.
|
|
//
|
|
// The content parameter should be an RFC 822-style email body. The lines of content should be CRLF terminated.
|
|
//
|
|
// Parameters:
|
|
// - addr: The hostname and port of the mail server, it must include a port, as in "mail.example.com:smtp".
|
|
// - auth: A AuthData pointer. If nil or if AuthData.Auth is set to false, not SMTP authentication will be performed.
|
|
// - from: The from address of the sender as string.
|
|
// - rcpts: A slice of strings of receipient addresses.
|
|
// - subject: The subject line as string.
|
|
// - content: A byte slice of the mail content
|
|
// - opts: Optional parameters for customizing the body part.
|
|
//
|
|
// Returns:
|
|
// - A pointer to the generated Msg.
|
|
// - An error if any step in the process of mail generation or delivery failed.
|
|
func QuickSend(addr string, auth *AuthData, from string, rcpts []string, subject string, content []byte) (*Msg, error) {
|
|
host, port, err := net.SplitHostPort(addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to split host and port from address: %w", err)
|
|
}
|
|
portnum, err := strconv.Atoi(port)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to convert port to int: %w", err)
|
|
}
|
|
client, err := NewClient(host, WithPort(portnum), WithTLSPolicy(TLSOpportunistic))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create new client: %w", err)
|
|
}
|
|
|
|
if auth != nil && auth.Auth {
|
|
client.SetSMTPAuth(SMTPAuthAutoDiscover)
|
|
client.SetUsername(auth.Username)
|
|
client.SetPassword(auth.Password)
|
|
}
|
|
|
|
tlsConfig := client.tlsconfig
|
|
if testHookTLSConfig != nil {
|
|
tlsConfig = testHookTLSConfig()
|
|
}
|
|
if err = client.SetTLSConfig(tlsConfig); err != nil {
|
|
return nil, fmt.Errorf("failed to set TLS config: %w", err)
|
|
}
|
|
|
|
message := NewMsg()
|
|
if err = message.From(from); err != nil {
|
|
return nil, fmt.Errorf("failed to set MAIL FROM address: %w", err)
|
|
}
|
|
if err = message.To(rcpts...); err != nil {
|
|
return nil, fmt.Errorf("failed to set RCPT TO address: %w", err)
|
|
}
|
|
message.Subject(subject)
|
|
buffer := bytes.NewBuffer(content)
|
|
writeFunc := writeFuncFromBuffer(buffer)
|
|
message.SetBodyWriter(TypeTextPlain, writeFunc)
|
|
|
|
if err = client.DialAndSend(message); err != nil {
|
|
return nil, fmt.Errorf("failed to dial and send message: %w", err)
|
|
}
|
|
return message, nil
|
|
}
|
|
|
|
// NewAuthData creates a new AuthData instance with the provided username and password.
|
|
//
|
|
// This function initializes an AuthData struct with authentication enabled and sets the
|
|
// username and password fields.
|
|
//
|
|
// Parameters:
|
|
// - user: The username for authentication.
|
|
// - pass: The password for authentication.
|
|
//
|
|
// Returns:
|
|
// - A pointer to the initialized AuthData instance.
|
|
func NewAuthData(user, pass string) *AuthData {
|
|
return &AuthData{
|
|
Auth: true,
|
|
Username: user,
|
|
Password: pass,
|
|
}
|
|
}
|