1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package module2021import (22 "context"2324 "github.com/emersion/go-message/textproto"25 "github.com/emersion/go-smtp"26 "github.com/foxcpp/maddy/framework/buffer"27)2829// DeliveryTarget interface represents abstract storage for the message data30// (typically persistent) or other kind of component that can be used as a31// final destination for the message.32//33// Modules implementing this interface should be registered with "target."34// prefix in name.35type DeliveryTarget interface {36 // Start starts the delivery of a new message.37 //38 // The domain part of the MAIL FROM address is assumed to be U-labels with39 // NFC normalization and case-folding applied. The message source should40 // ensure that by calling address.CleanDomain if necessary.41 Start(ctx context.Context, msgMeta *MsgMetadata, mailFrom string) (Delivery, error)42}4344type Delivery interface {45 // AddRcpt adds the target address for the message.46 //47 // The domain part of the address is assumed to be U-labels with NFC normalization48 // and case-folding applied. The message source should ensure that by49 // calling address.CleanDomain if necessary.50 //51 // Implementation should assume that no case-folding or deduplication was52 // done by caller code. Its implementation responsibility to do so if it is53 // necessary. It is not recommended to reject duplicated recipients,54 // however. They should be silently ignored.55 //56 // Implementation should do as much checks as possible here and reject57 // recipients that can't be used. Note: MsgMetadata object passed to Start58 // contains BodyLength field. If it is non-zero, it can be used to check59 // storage quota for the user before Body.60 AddRcpt(ctx context.Context, rcptTo string, opts smtp.RcptOptions) error6162 // Body sets the body and header contents for the message.63 // If this method fails, message is assumed to be undeliverable64 // to all recipients.65 //66 // Implementation should avoid doing any persistent changes to the67 // underlying storage until Commit is called. If that is not possible,68 // Abort should (attempt to) rollback any such changes.69 //70 // If Body can't be implemented without per-recipient failures,71 // then delivery object should also implement PartialDelivery interface72 // for use by message sources that are able to make sense of per-recipient73 // errors.74 //75 // Here is the example of possible implementation for maildir-based76 // storage:77 // Calling Body creates a file in tmp/ directory.78 // Commit moves the created file to new/ directory.79 // Abort removes the created file.80 Body(ctx context.Context, header textproto.Header, body buffer.Buffer) error8182 // Abort cancels message delivery.83 //84 // All changes made to the underlying storage should be aborted at this85 // point, if possible.86 Abort(ctx context.Context) error8788 // Commit completes message delivery.89 //90 // It generally should never fail, since failures here jeopardize91 // atomicity of the delivery if multiple targets are used.92 Commit(ctx context.Context) error93}