Skip to content

Commit e8b7e9d

Browse files
committed
Initial commit
0 parents  commit e8b7e9d

22 files changed

+1415
-0
lines changed

.editorconfig

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
; This file is for unifying the coding style for different editors and IDEs.
2+
; More information at http://editorconfig.org
3+
4+
root = true
5+
6+
[*]
7+
charset = utf-8
8+
end_of_line = lf
9+
indent_size = 4
10+
indent_style = space
11+
insert_final_newline = true
12+
trim_trailing_whitespace = true
13+
14+
; Works with some editors only
15+
max_line_length = 120
16+
spaces_around_brackets = true
17+
spaces_around_operators = true
18+
19+
[{*.go,Makefile}]
20+
indent_style = tab
21+
22+
[*.{yml,yaml}]
23+
indent_size = 2

.env.dist

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
SERVER_HOST=localhost
2+
SERVER_PORT=8080
3+
SERVER_SHUTDOWN_TIMEOUT=5
4+
HTTP_TRACE_HEADER=X-Amzn-Trace-Id
5+
SMTP_HOST=localhost
6+
SMTP_PORT=1025
7+
LOG_LEVEL=info

.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export GO111MODULE=on

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env

Dockerfile

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM golang:1-alpine AS builder
2+
RUN apk --update add ca-certificates
3+
RUN update-ca-certificates
4+
ARG version
5+
LABEL version=${version}
6+
WORKDIR /go/src/github.com/eexit/httpsmtp
7+
COPY . .
8+
# Inject the build version: https://blog.alexellis.io/inject-build-time-vars-golang/
9+
RUN CGO_ENABLED=0 GOOS=linux go build \
10+
-ldflags "-X github.com/eexit/httpsmtp/internal/server.Version=${version}" \
11+
-o /httpsmtp \
12+
./cmd/httpsmtp
13+
14+
FROM scratch
15+
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
16+
EXPOSE 8080
17+
COPY --from=builder /httpsmtp /
18+
CMD ["/httpsmtp"]

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# HTTP <> SMTP
2+
3+
This project allows to plug any HTTP-based mailer to any SMTP server, like MailHog or MailCatcher.

cmd/httpsmtp/httpsmtp.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import (
4+
"math/rand"
5+
"os"
6+
"time"
7+
8+
"github.com/eexit/httpsmtp/internal/env"
9+
"github.com/eexit/httpsmtp/internal/server"
10+
"github.com/kelseyhightower/envconfig"
11+
)
12+
13+
func main() {
14+
rand.Seed(time.Now().UTC().UnixNano())
15+
16+
var e env.Bag
17+
envconfig.MustProcess("", &e)
18+
19+
server := server.New(e)
20+
if err := server.Serve(); err != nil {
21+
panic(err)
22+
}
23+
os.Exit(0)
24+
}

go.mod

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module github.com/eexit/httpsmtp
2+
3+
go 1.15
4+
5+
require (
6+
github.com/go-playground/validator/v10 v10.4.1
7+
github.com/gorilla/mux v1.8.0
8+
github.com/justinas/alice v1.2.0
9+
github.com/kelseyhightower/envconfig v1.4.0
10+
github.com/rs/zerolog v1.20.0
11+
)

go.sum

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
2+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
3+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
5+
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
6+
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
7+
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
8+
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
9+
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
10+
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
11+
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
12+
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
13+
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
14+
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
15+
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
16+
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
17+
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
18+
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
19+
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
20+
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
21+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
22+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
23+
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
24+
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
25+
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
26+
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
27+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
28+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
29+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
30+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
31+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
32+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
33+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
34+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
35+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
36+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
37+
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
38+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
39+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
40+
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
41+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
42+
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
43+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
44+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
45+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
46+
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
47+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

internal/converter/converter.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package converter
2+
3+
import (
4+
"io"
5+
)
6+
7+
// Converter converts an input to a ConvertedMessage
8+
type Converter interface {
9+
Convert(data io.ReadSeeker) (*Message, error)
10+
}

internal/converter/message.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package converter
2+
3+
import (
4+
"io"
5+
"io/ioutil"
6+
)
7+
8+
// RecipientProvider is the common func type for To(), Cc() and Bcc()
9+
type RecipientProvider func(*Message) []string
10+
11+
// Message represents an email message
12+
type Message struct {
13+
from string
14+
to, cc, bcc []string
15+
raw io.Reader
16+
}
17+
18+
// NewMessage returns a new Message instance
19+
func NewMessage(from string, to, cc, bcc []string, raw io.Reader) *Message {
20+
return &Message{
21+
from: from,
22+
to: to,
23+
cc: cc,
24+
bcc: bcc,
25+
raw: raw,
26+
}
27+
}
28+
29+
// From returns the message's From: value
30+
func (m *Message) From() string {
31+
return m.from
32+
}
33+
34+
// To returns the To: recipient(s)
35+
func (m *Message) To() []string {
36+
return m.to
37+
}
38+
39+
// Cc returns the Cc: recipient(s)
40+
func (m *Message) Cc() []string {
41+
return m.cc
42+
}
43+
44+
// Bcc returns the Bcc: recipient(s)
45+
func (m *Message) Bcc() []string {
46+
return m.bcc
47+
}
48+
49+
// Raw returns the raw message (with its headers) as a byte stream
50+
func (m *Message) Raw() ([]byte, error) {
51+
return ioutil.ReadAll(m.raw)
52+
}
53+
54+
// HasRecipients returns true if the message contains as least one recipient
55+
// amongst To, Cc and Bcc.
56+
func (m *Message) HasRecipients() bool {
57+
return len(m.to)+len(m.cc)+len(m.bcc) > 0
58+
}

0 commit comments

Comments
 (0)