mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-22 13:50:49 +01:00
Makeing some progress...
This commit is contained in:
parent
4dd9c1bf40
commit
261481344f
5 changed files with 190 additions and 18 deletions
9
.idea/markdown.xml
Normal file
9
.idea/markdown.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MarkdownSettings">
|
||||||
|
<enabledExtensions>
|
||||||
|
<entry key="MermaidLanguageExtension" value="false" />
|
||||||
|
<entry key="PlantUMLLanguageExtension" value="false" />
|
||||||
|
</enabledExtensions>
|
||||||
|
</component>
|
||||||
|
</project>
|
147
client.go
147
client.go
|
@ -2,10 +2,16 @@ package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/smtp"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultPort is the default connection port to the SMTP server
|
// DefaultPort is the default connection port cto the SMTP server
|
||||||
const DefaultPort = 25
|
const DefaultPort = 25
|
||||||
|
|
||||||
// DefaultTimeout is the default connection timeout
|
// DefaultTimeout is the default connection timeout
|
||||||
|
@ -13,19 +19,50 @@ const DefaultTimeout = time.Second * 30
|
||||||
|
|
||||||
// Client is the SMTP client struct
|
// Client is the SMTP client struct
|
||||||
type Client struct {
|
type Client struct {
|
||||||
h string // Hostname of the target SMTP server to connect to
|
// Hostname of the target SMTP server cto connect cto
|
||||||
p int // Port of the SMTP server to connect to
|
host string
|
||||||
s bool // Use SSL/TLS or not
|
|
||||||
ctx context.Context // The context for the connection handling
|
// Port of the SMTP server cto connect cto
|
||||||
|
port int
|
||||||
|
|
||||||
|
// Use SSL for the connection
|
||||||
|
ssl bool
|
||||||
|
|
||||||
|
// Sets the client cto use STARTTTLS for the connection (is disabled when SSL is set)
|
||||||
|
starttls bool
|
||||||
|
|
||||||
|
// Timeout for the SMTP server connection
|
||||||
|
cto time.Duration
|
||||||
|
|
||||||
|
// HELO/EHLO string for the greeting the target SMTP server
|
||||||
|
helo string
|
||||||
|
|
||||||
|
// The SMTP client that is set up when using the Dial*() methods
|
||||||
|
sc *smtp.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option returns a function that can be used for grouping Client options
|
// Option returns a function that can be used for grouping Client options
|
||||||
type Option func(*Client)
|
type Option func(*Client)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNoHostname should be used if a Client has no hostname set
|
||||||
|
ErrNoHostname = errors.New("hostname for client cannot be empty")
|
||||||
|
|
||||||
|
// ErrInvalidHostname should be used if a Client has an invalid hostname set
|
||||||
|
//ErrInvalidHostname = errors.New("hostname for client is invalid")
|
||||||
|
)
|
||||||
|
|
||||||
// NewClient returns a new Session client object
|
// NewClient returns a new Session client object
|
||||||
func NewClient(o ...Option) Client {
|
func NewClient(h string, o ...Option) (*Client, error) {
|
||||||
c := Client{
|
c := &Client{
|
||||||
p: DefaultPort,
|
host: h,
|
||||||
|
port: DefaultPort,
|
||||||
|
cto: DefaultTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default HELO/EHLO hostname
|
||||||
|
if err := c.setDefaultHelo(); err != nil {
|
||||||
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override defaults with optionally provided Option functions
|
// Override defaults with optionally provided Option functions
|
||||||
|
@ -33,26 +70,100 @@ func NewClient(o ...Option) Client {
|
||||||
if co == nil {
|
if co == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
co(&c)
|
co(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
// Some settings in a Client cannot be empty/unset
|
||||||
}
|
if c.host == "" {
|
||||||
|
return c, ErrNoHostname
|
||||||
|
|
||||||
// WithHost overrides the default connection port
|
|
||||||
func WithHost(h string) Option {
|
|
||||||
return func(c *Client) {
|
|
||||||
c.h = h
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithPort overrides the default connection port
|
// WithPort overrides the default connection port
|
||||||
func WithPort(p int) Option {
|
func WithPort(p int) Option {
|
||||||
return func(c *Client) {
|
return func(c *Client) {
|
||||||
c.p = p
|
c.port = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Client) Dial() {
|
// WithTimeout overrides the default connection timeout
|
||||||
|
func WithTimeout(t time.Duration) Option {
|
||||||
|
return func(c *Client) {
|
||||||
|
c.cto = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSSL tells the client to use a SSL/TLS connection
|
||||||
|
func WithSSL() Option {
|
||||||
|
return func(c *Client) {
|
||||||
|
c.ssl = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial establishes a connection cto the SMTP server with a default context.Background
|
||||||
|
func (c *Client) Dial() error {
|
||||||
|
ctx := context.Background()
|
||||||
|
return c.DialWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialWithContext establishes a connection cto the SMTP server with a given context.Context
|
||||||
|
func (c *Client) DialWithContext(uctx context.Context) error {
|
||||||
|
ctx, cfn := context.WithTimeout(uctx, c.cto)
|
||||||
|
defer cfn()
|
||||||
|
|
||||||
|
nd := net.Dialer{}
|
||||||
|
td := tls.Dialer{}
|
||||||
|
var co net.Conn
|
||||||
|
var err error
|
||||||
|
if c.ssl {
|
||||||
|
co, err = td.DialContext(ctx, "tcp", fmt.Sprintf("%s:%d", c.host, c.port))
|
||||||
|
}
|
||||||
|
if !c.ssl {
|
||||||
|
co, err = nd.DialContext(ctx, "tcp", fmt.Sprintf("%s:%d", c.host, c.port))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.sc, err = smtp.NewClient(co, c.host)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.sc.Hello(c.helo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sends out the mail message
|
||||||
|
func (c *Client) Send() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection cto the SMTP server
|
||||||
|
func (c *Client) Close() error {
|
||||||
|
if err := c.sc.Close(); err != nil {
|
||||||
|
fmt.Printf("failed close: %s\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ok, auth := c.sc.Extension("PIPELINING"); ok {
|
||||||
|
fmt.Printf("PIPELINING Support: %s\n", auth)
|
||||||
|
} else {
|
||||||
|
fmt.Println("No PIPELINING")
|
||||||
|
}
|
||||||
|
return c.sc.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setDefaultHelo retrieves the current hostname and sets it as HELO/EHLO hostname
|
||||||
|
func (c *Client) setDefaultHelo() error {
|
||||||
|
hn, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed cto read local hostname: %w", err)
|
||||||
|
}
|
||||||
|
c.helo = hn
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
31
cmd/main.go
Normal file
31
cmd/main.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/wneessen/go-mail"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c, err := mail.NewClient("192.168.178.60", mail.WithTimeout(time.Millisecond*500), mail.WithSSL())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to create new client: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cfn := context.WithCancel(context.Background())
|
||||||
|
defer cfn()
|
||||||
|
|
||||||
|
if err := c.DialWithContext(ctx); err != nil {
|
||||||
|
fmt.Printf("failed to dial: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Client: %+v\n", c)
|
||||||
|
time.Sleep(time.Millisecond * 1500)
|
||||||
|
if err := c.Close(); err != nil {
|
||||||
|
fmt.Printf("failed to close SMTP connection: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
2
doc.go
Normal file
2
doc.go
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// Package mail provides a simple and easy way cto sending mails with Go
|
||||||
|
package mail
|
19
tls.go
Normal file
19
tls.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package mail
|
||||||
|
|
||||||
|
// TLSPolicy type describes a int alias for the different TLS policies we allow
|
||||||
|
type TLSPolicy int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TLSMandatory requires that the connection cto the server is
|
||||||
|
// encrypting using STARTTLS. If the server does not support STARTTLS
|
||||||
|
// the connection will be terminated with an error
|
||||||
|
TLSMandatory TLSPolicy = iota
|
||||||
|
|
||||||
|
// TLSOpportunistic tries cto establish an encrypted connection via the
|
||||||
|
// STARTTLS protocol. If the server does not support this, it will fall
|
||||||
|
// back cto non-encrypted plaintext transmission
|
||||||
|
TLSOpportunistic
|
||||||
|
|
||||||
|
// NoTLS forces the transaction cto be not encrypted
|
||||||
|
NoTLS
|
||||||
|
)
|
Loading…
Reference in a new issue