Skip to content

Commit 9f0961d

Browse files
committed
Add options to enable tls
1 parent 0da131f commit 9f0961d

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Options:
6565
| SMTP domain | `--smtp-domain` | `SMTP_DOMAIN` | `localhost` |
6666
| SMTP incoming password | `--smtp-incoming-pass` | `SMTP_INCOMING_PASS` | |
6767
| SMTP incoming username | `--smtp-incoming-user` | `SMTP_INCOMING_USER` | |
68+
| SMTP TLS | `--smtp-tls` | `SMTP_TLS` | `false` |
6869

6970
_Note that authentication is only enabled if you provided the relevant envourment variables_
7071

go/email_server.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@ package src
22

33
import (
44
"bytes"
5+
cryptoRand "crypto/rand"
6+
"crypto/rsa"
7+
"crypto/tls"
8+
"crypto/x509"
9+
"crypto/x509/pkix"
510
"fmt"
611
"io"
712
"log"
13+
"math/big"
814
"math/rand"
15+
"net"
16+
"os"
917
"sync"
1018
"time"
1119

@@ -148,6 +156,7 @@ type StartEmailServerOptions struct {
148156
Username string
149157
Password string
150158
MaxEmails uint16
159+
Tls bool
151160
}
152161

153162
// StartEmailServer starts the email server
@@ -179,9 +188,72 @@ func StartEmailServer(opts StartEmailServerOptions) {
179188
server.AllowInsecureAuth = true
180189
server.AuthDisabled = backend.Credentials == nil
181190

191+
if opts.Tls {
192+
tlsConfig, err := generateTLSConfig()
193+
if err != nil {
194+
fmt.Println("WARN: failed to generate self signed tls certificate for email server, error:", err)
195+
os.Exit(1)
196+
} else {
197+
server.TLSConfig = tlsConfig
198+
}
199+
}
200+
182201
fmt.Println("Running SMTP server at", server.Addr, "with a emails dequeue length of", opts.MaxEmails)
183202
err := server.ListenAndServe()
184203
if err != nil {
185204
log.Fatal(err)
186205
}
187206
}
207+
208+
func generateTLSConfig() (*tls.Config, error) {
209+
// Generate a private key
210+
privateKey, err := rsa.GenerateKey(cryptoRand.Reader, 2048)
211+
if err != nil {
212+
return nil, err
213+
}
214+
215+
// Set up certificate template
216+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
217+
serialNumber, err := cryptoRand.Int(cryptoRand.Reader, serialNumberLimit)
218+
if err != nil {
219+
return nil, err
220+
}
221+
222+
template := x509.Certificate{
223+
SerialNumber: serialNumber,
224+
Subject: pkix.Name{
225+
Organization: []string{"Self-Signed Cert"},
226+
CommonName: "localhost",
227+
},
228+
NotBefore: time.Now(),
229+
NotAfter: time.Now().AddDate(1, 0, 0),
230+
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
231+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
232+
BasicConstraintsValid: true,
233+
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
234+
DNSNames: []string{"localhost"},
235+
}
236+
237+
// Create the certificate
238+
derBytes, err := x509.CreateCertificate(
239+
cryptoRand.Reader,
240+
&template,
241+
&template,
242+
&privateKey.PublicKey,
243+
privateKey,
244+
)
245+
if err != nil {
246+
return nil, err
247+
}
248+
249+
// Create the TLS certificate
250+
cert := tls.Certificate{
251+
Certificate: [][]byte{derBytes},
252+
PrivateKey: privateKey,
253+
}
254+
255+
// Return the TLS config
256+
return &tls.Config{
257+
Certificates: []tls.Certificate{cert},
258+
}, nil
259+
}

main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func main() {
3232
argSMTPDomain := pflag.String("smtp-domain", defaultSMPTDomain, "SMTP server domain")
3333
argSMTPUsername := pflag.String("smtp-incoming-user", "", "SMTP server username"+ifEmptyNotRequired)
3434
argSMTPPassword := pflag.String("smtp-incoming-pass", "", "SMTP server password"+ifEmptyNotRequired)
35+
argSMTPTLS := pflag.Bool("smtp-tls", false, "Enable TLS for SMTP server")
3536
argHTTPUsername := pflag.String("http-user", "", "HTTP server username"+ifEmptyNotRequired)
3637
argHTTPPassword := pflag.String("http-pass", "", "HTTP server address"+ifEmptyNotRequired)
3738
argDisableWeb := pflag.Bool("disable-web", false, "Disable the web interface")
@@ -43,6 +44,7 @@ func main() {
4344
envSMTPDomain := getenv("SMTP_DOMAIN")
4445
envSMTPUsername := getenv("SMTP_INCOMING_USER")
4546
envSMTPPassword := getenv("SMTP_INCOMING_PASS")
47+
envSMTPTLS := strings.ToLower(getenv("SMTP_TLS")) == "true"
4648
envHTTPUsername := getenv("HTTP_USER")
4749
envHTTPPassword := getenv("HTTP_PASS")
4850
envDisableWeb := strings.ToLower(getenv("DISABLE_WEB")) == "true"
@@ -77,6 +79,9 @@ func main() {
7779
if !*argDisableWeb && envDisableWeb {
7880
*argDisableWeb = envDisableWeb
7981
}
82+
if *argSMTPTLS == false && envSMTPTLS {
83+
*argSMTPTLS = envSMTPTLS
84+
}
8085

8186
if *argDisableWeb {
8287
fmt.Println("Not starting webserver as --disable-web is set")
@@ -93,5 +98,6 @@ func main() {
9398
Username: *argSMTPUsername,
9499
Password: *argSMTPPassword,
95100
MaxEmails: *argMaxEmails,
101+
Tls: *argSMTPTLS,
96102
})
97103
}

0 commit comments

Comments
 (0)