-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathenvelope.go
More file actions
92 lines (81 loc) · 2.05 KB
/
envelope.go
File metadata and controls
92 lines (81 loc) · 2.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package main
import (
"bytes"
"github.com/igrmk/go-smtpd/smtpd"
"github.com/jhillyerd/enmime"
)
type env struct {
*smtpd.BasicEnvelope
from smtpd.MailAddress
data []byte
mime *enmime.Envelope
host string
chatIDs map[int64]bool
chatForUsernameCh chan<- chatForUsernameArgs
deliverCh chan<- deliverArgs
maxSize int
}
type chatForUsernameResult struct {
chatID int64
err error
}
type chatForUsernameArgs struct {
result chan chatForUsernameResult
username string
}
type deliverArgs struct {
result chan error
env *env
}
// Close implements smtpd.Envelope.Close
func (e *env) Close() error {
if len(e.chatIDs) == 0 {
return smtpd.SMTPError("550 bad recipient")
}
mime, err := enmime.ReadEnvelope(bytes.NewReader(e.data))
if err != nil {
return err
}
e.mime = mime
if err := e.deliver(); err != nil {
return err
}
return nil
}
// Write implements smtpd.Envelope.Write
func (e *env) Write(line []byte) error {
e.data = append(e.data, line...)
if len(e.data) > e.maxSize {
return smtpd.SMTPError("552 5.3.4 message too big")
}
return nil
}
// AddRecipient implements smtpd.Envelope.AddRecipient
func (e *env) AddRecipient(rcpt smtpd.MailAddress) error {
username, host := splitAddress(rcpt.Email())
if host != e.host {
return smtpd.SMTPError("550 bad recipient")
}
chatID, err := e.chatForUsername(username)
if err == errorMuted {
return smtpd.SMTPError("550 bad recipient")
}
if err == errorTooManyEmails {
return smtpd.SMTPError("452 too many emails")
}
e.chatIDs[chatID] = true
return e.BasicEnvelope.AddRecipient(rcpt)
}
func (e *env) deliver() error {
result := make(chan error)
defer close(result)
e.deliverCh <- deliverArgs{result: result, env: e}
return <-result
}
func (e *env) chatForUsername(username string) (int64, error) {
resultCh := make(chan chatForUsernameResult)
defer close(resultCh)
e.chatForUsernameCh <- chatForUsernameArgs{result: resultCh, username: username}
result := <-resultCh
return result.chatID, result.err
}