maddy/framework/module/msgmetadata.go

151 lines
5.6 KiB
Go

/*
Maddy Mail Server - Composable all-in-one email server.
Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package module
import (
"crypto/rand"
"encoding/hex"
"io"
"github.com/emersion/go-smtp"
"github.com/foxcpp/maddy/framework/future"
)
// ConnState structure holds the state information of the protocol used to
// accept this message.
type ConnState struct {
// IANA name (ESMTP, ESMTPS, etc) of the protocol message was received
// over. If the message was generated locally, this field is empty.
Proto string
// Information about the SMTP connection, including HELO hostname and
// source IP. Valid only if Proto refers the SMTP protocol or its variant
// (e.g. LMTP).
smtp.ConnectionState
// The RDNSName field contains the result of Reverse DNS lookup on the
// client IP.
//
// The underlying type is the string or untyped nil value. It is the
// message source responsibility to populate this field.
//
// Valid values of this field consumers need to be aware of:
// RDNSName = nil
// The reverse DNS lookup is not applicable for that message source.
// Typically the case for messages generated locally.
// RDNSName != nil, but Get returns nil
// The reverse DNS lookup was attempted, but resulted in an error.
// Consumers should assume that the PTR record doesn't exist.
RDNSName *future.Future
// If the client successfully authenticated using a username/password pair.
// This field contains the username.
AuthUser string
// If the client successfully authenticated using a username/password pair.
// This field should be cleaned if the ConnState object is serialized
AuthPassword string
}
// MsgMetadata structure contains all information about the origin of
// the message and all associated flags indicating how it should be handled
// by components.
//
// All fields should be considered read-only except when otherwise is noted.
// Module instances should avoid keeping reference to the instance passed to it
// and copy the structure using DeepCopy method instead.
//
// Compatibility with older values should be considered when changing this
// structure since it is serialized to the disk by the queue module using
// JSON. Modules should correctly handle missing or invalid values.
type MsgMetadata struct {
// Unique identifier for this message. Randomly generated by the
// message source module.
ID string
// Original message sender address as it was received by the message source.
//
// Note that this field is meant for use for tracing purposes.
// All routing and other decisions should be made based on the sender address
// passed separately (for example, mailFrom argument for CheckSender function)
// Note that addresses may contain unescaped Unicode characters.
OriginalFrom string
// If set - no SrcHostname and SrcAddr will be added to Received
// header. These fields are still written to the server log.
DontTraceSender bool
// Quarantine is a message flag that is should be set if message is
// considered "suspicious" and should be put into "Junk" folder
// in the storage.
//
// This field should not be modified by the checks that verify
// the message. It is set only by the message pipeline.
Quarantine bool
// OriginalRcpts contains the mapping from the final recipient to the
// recipient that was presented by the client.
//
// MsgPipeline will update that field when recipient modifiers
// are executed.
//
// It should be used when reporting information back to client (via DSN,
// for example) to prevent disclosing information about aliases
// which is usually unwanted.
OriginalRcpts map[string]string
// SMTPOpts contains the SMTP MAIL FROM command arguments, if the message
// was accepted over SMTP or SMTP-like protocol (such as LMTP).
//
// Note that the Size field should not be used as source of information about
// the body size. Especially since it counts the header too whereas
// Buffer.Len does not.
SMTPOpts smtp.MailOptions
// Conn contains the information about the underlying protocol connection
// that was used to accept this message. The referenced instance may be shared
// between multiple messages.
//
// It can be nil for locally generated messages.
Conn *ConnState
// This is set by endpoint/smtp to indicate that body contains "TLS-Required: No"
// header. It is only meaningful if server has seen the body at least once
// (e.g. the message was passed via queue).
TLSRequireOverride bool
}
// DeepCopy creates a copy of the MsgMetadata structure, also
// copying contents of the maps and slices.
//
// There are a few exceptions, however:
// - SrcAddr is not copied and copy field references original value.
func (msgMeta *MsgMetadata) DeepCopy() *MsgMetadata {
cpy := *msgMeta
// There is no good way to copy net.Addr, but it should not be
// modified by anything anyway so we are safe.
return &cpy
}
// GenerateMsgID generates a string usable as MsgID field in module.MsgMeta.
func GenerateMsgID() (string, error) {
rawID := make([]byte, 4)
_, err := io.ReadFull(rand.Reader, rawID)
return hex.EncodeToString(rawID), err
}