Help us shape the future of Go! Take the 2026 Go Developer Survey

mail

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package mail registers the mail bindings: the mail() function and the Mail class, both of which deliver through a server the host configured and named.

A script names a server. It does not spell one: there is no way to hand a host, a username or a password to a binding, and no way to read one back out of the object a binding returns. The credentials live in a model.MailProvider the host builds from its configuration, which reads them at the moment of a delivery and hands back nothing but the outcome.

SMTP is the protocol the package speaks, not the subject it models, so it names the conversation in provider.go and nothing a script types.

Index

Constants

View Source
const DefaultName = "default"

DefaultName is the server a script that names none asks for. `new Mail` and mail() both resolve it.

View Source
const DefaultPort = 25

DefaultPort is the port a server that names none is reached on. It is the plain SMTP port; a submission host usually wants 587.

Variables

Default is the provider used when a runtime's options name none. It holds no servers, so mail() and `new Mail` refuse catchably naming what is missing, which is what a CLI run with no mail block has.

Functions

func Register

func Register(rt *runner.Runtime)

Register installs the mail bindings on rt.

Types

type Config

type Config struct {
	Host     string `yaml:"host" json:"host"`
	Port     int    `yaml:"port" json:"port"`
	Username string `yaml:"username" json:"username"`
	Password string `yaml:"password" json:"password"`
	From     string `yaml:"from" json:"from"`

	// Insecure accepts the STARTTLS certificate without verifying its chain or
	// names. Hosts that present a self-signed certificate, or one carrying no
	// subjectAltName, are unreachable without it.
	Insecure bool `yaml:"insecure" json:"insecure"`
}

Config contains the connection and sender settings for one mail server.

It is host configuration and never reaches a script: a provider holds it, reads it inside a delivery, and hands back nothing but the outcome. Config is not a binding return type anywhere, which is what keeps a password out of the runtime scope.

func (Config) String

func (c Config) String() string

String renders the settings that identify a server and elides the two that authenticate to it.

Nothing formats a Config today. The method is here so that nothing can start to by accident: a %v in an error or a log line is the cheapest way for a password to escape the process, and this makes that spelling harmless permanently. It does not affect the yaml decoder, which reads the fields.

func (Config) Validate

func (c Config) Validate(name string) error

Validate reports whether the server is usable, naming it.

Host and From are the operator's to get right, so they are checked when the configuration is read and fail the server at startup. Leaving it to the first delivery means finding out from a @schedule job at three in the morning, on the one code path nobody is watching.

type Deliver

type Deliver func(config Config, recipient, subject, body string) error

Deliver hands one message to a transport, with the credential of the server it resolved to. It is the seam a host swaps to send by something other than SMTP, and it is a function rather than another MailProvider because the name resolution and the tenant isolation sit above it and are not to be reimplemented. A Deliver is host code and is handed the host's settings.

type Mail

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

Mail is the handle a script holds on one configured server.

Both fields are unexported, which is what makes the object opaque from PHP: a binding publishes its exported methods and fields, so $mail->password, var_dump, print_r, get_object_vars and json_encode all find nothing. The only thing it can do is send, and the only thing it knows is a name.

func (*Mail) Send

func (m *Mail) Send(ctx context.Context, recipient, subject, body string) error

Send sends an email through the server this client names. It takes a context so the delivery is recorded on the trace of the request that asked for it; the runtime injects it, so a script still calls `$mail->send($to, $subject, $body)`.

type Memory

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

Memory is a Provider that appends messages to an in-memory queue instead of delivering them. A host binds one through runner.Options.Mail to capture what scripts send: tests, local runs, dry runs.

It is a provider rather than a sender spliced in further down, so a test using it still goes through name resolution and still exercises the refusal a script gets for a server nobody configured.

func NewMemory

func NewMemory(names ...string) *Memory

NewMemory creates an empty in-memory provider configured for the given server names. Naming none configures every name, which is the capture everything a dry run wants; naming some lets a test assert the refusal for the rest.

func (*Memory) Configured

func (m *Memory) Configured(name string) error

Configured reports why name cannot be delivered through, and nil when it can.

func (*Memory) Messages

func (m *Memory) Messages() []Message

Messages returns the queued messages in send order.

func (*Memory) Next

func (m *Memory) Next() (Message, bool)

Next pops the oldest queued message, reporting whether one was queued.

func (*Memory) Reset

func (m *Memory) Reset()

Reset empties the queue.

func (*Memory) Send

func (m *Memory) Send(_ context.Context, name, recipient, subject, body string) error

Send queues a message, reporting the same refusal a real delivery would for a server this provider does not hold.

type Message

type Message struct {
	Server    string
	Recipient string
	Subject   string
	Body      string
}

Message is a queued email, with the name of the server it was addressed to.

type Provider

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

Provider holds the credentials of a set of named mail servers.

The map is fixed once the provider is built. There is deliberately no registration call and no listing call: a script names a server and learns only whether the delivery worked. That is also what lets the constructor check a name without the answer being able to disagree with the one Send makes for itself.

func NewProvider

func NewProvider(servers map[string]Config) *Provider

NewProvider returns a provider holding the given servers, keyed by the name a script asks for, delivering over SMTP.

func NewProviderFunc

func NewProviderFunc(servers map[string]Config, deliver Deliver) *Provider

NewProviderFunc is NewProvider with the transport replaced, the way database.NewDatabaseProvider takes its connector. A nil deliver is SMTP.

The map is copied rather than retained, because config layering hands one map to every site that declared no mail block and a normalisation written into it would be written into all of them. Names are lowercased and a missing port is filled in here, so a delivery reads a complete credential.

func (*Provider) Configured

func (p *Provider) Configured(name string) error

Configured reports why name cannot be delivered through, and nil when it can.

func (*Provider) Send

func (p *Provider) Send(_ context.Context, name, recipient, subject, body string) error

Send delivers one message through the named server.

The credential is read here, into a local, and is gone when the call returns. Nothing that outlives the delivery holds it: not the PHP object the script called, not the span, not the error.

Jump to

Keyboard shortcuts

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