├── .travis.yml ├── docs ├── MailHog.png ├── example-auth ├── APIv2.md ├── BUILD.md ├── Auth.md ├── APIv1.md ├── DEPLOY.md ├── JIM.md ├── CONFIG.md ├── RELEASES.md └── APIv2 │ ├── swagger-2.0.yaml │ └── swagger-2.0.json ├── Dockerfile ├── config └── config.go ├── LICENSE.md ├── Makefile ├── README.md └── main.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.4 4 | - tip 5 | -------------------------------------------------------------------------------- /docs/MailHog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phase2/MailHog/master/docs/MailHog.png -------------------------------------------------------------------------------- /docs/example-auth: -------------------------------------------------------------------------------- 1 | test:$2a$04$qxRo.ftFoNep7ld/5jfKtuBTnGqff/fZVyj53mUC5sVf9dtDLAi/S 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.4 2 | 3 | RUN go get github.com/mailhog/MailHog 4 | 5 | EXPOSE 1025 8025 6 | 7 | ENTRYPOINT ["/go/bin/MailHog"] 8 | -------------------------------------------------------------------------------- /docs/APIv2.md: -------------------------------------------------------------------------------- 1 | MailHog API v2 2 | ============== 3 | 4 | The v2 API is hopefully less of a mess than v1. 5 | 6 | The specification is written in [Swagger 2.0](http://swagger.io/). 7 | 8 | See the YAML and JSON specifications in the [APIv2](./APIv2) directory. 9 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/ian-kent/envconf" 7 | ) 8 | 9 | func DefaultConfig() *Config { 10 | return &Config{ 11 | AuthFile: "", 12 | } 13 | } 14 | 15 | type Config struct { 16 | AuthFile string 17 | } 18 | 19 | var cfg = DefaultConfig() 20 | 21 | func Configure() *Config { 22 | return cfg 23 | } 24 | 25 | func RegisterFlags() { 26 | flag.StringVar(&cfg.AuthFile, "auth-file", envconf.FromEnvP("MH_AUTH_FILE", "").(string), "A username:bcryptpw mapping file") 27 | } 28 | -------------------------------------------------------------------------------- /docs/BUILD.md: -------------------------------------------------------------------------------- 1 | Building MailHog 2 | ================ 3 | 4 | MailHog is built using `make`, and using [this Makefile](Makefile). 5 | 6 | If you aren't making any code changes, you can install MailHog using 7 | `go get github.com/mailhog/MailHog`, since [assets.go](MailHog-UI/assets/assets.go) 8 | is already pre-compiled and committed to this repository. 9 | 10 | ### Why do I need a Makefile? 11 | 12 | MailHog has HTML, CSS and Javascript assets which need to be converted 13 | to a go source file using [go-bindata](https://github.com/jteeuwen/go-bindata). 14 | 15 | This must happen before running `go build` or `go install` to avoid compilation 16 | errors (e.g., `no buildable Go source files in MailHog-UI/assets`). 17 | 18 | ### go generate 19 | 20 | The build should be updated to use `go generate` (added in Go 1.4) to 21 | preprocess static assets into go source files. 22 | 23 | However, this will break backwards compatibility with Go 1.2/1.3. 24 | 25 | ### Building a release 26 | 27 | Releases are built using [gox](https://github.com/mitchellh/gox). 28 | 29 | Run `make release` to cross-compile for all available platforms. 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ian Kent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/Auth.md: -------------------------------------------------------------------------------- 1 | Authentication 2 | ============== 3 | 4 | HTTP basic authentication is supported using a password file. 5 | 6 | See [example-auth](example-auth) for an example (the password is `test`). 7 | 8 | Authentication applies to all HTTP requests, including static content 9 | and API endpoints. 10 | 11 | ### Password file format 12 | 13 | The password file format is: 14 | 15 | * One user per line 16 | * `username:password` 17 | * Password is bcrypted 18 | 19 | By default, a bcrypt difficulty of 4 is used to reduce page load times. 20 | 21 | ### Generating a bcrypted password 22 | 23 | You can use a MailHog shortcut to generate a bcrypted password: 24 | 25 | MailHog bcrypt 26 | 27 | ### Enabling HTTP authentication 28 | 29 | To enable authentication, pass an `-auth-file` flag to MailHog: 30 | 31 | MailHog -auth-file=docs/example-auth 32 | 33 | This also works if you're running MailHog-UI and MailHog-Server separately: 34 | 35 | MailHog-Server -auth-file=docs/example-auth 36 | MailHog-UI -auth-file=docs/example-auth 37 | 38 | ## Future compatibility 39 | 40 | Authentication has been a bit of an experiment. 41 | 42 | The exact implementation may change over time, e.g. using sessions in the UI 43 | and tokens for the API to avoid frequently bcrypting passwords. 44 | -------------------------------------------------------------------------------- /docs/APIv1.md: -------------------------------------------------------------------------------- 1 | MailHog API v1 2 | ============== 3 | 4 | The v1 API is a RESTful HTTP JSON API. 5 | 6 | ### GET /api/v1/events 7 | 8 | Streams new messages using EventSource and chunked encoding 9 | 10 | ### GET /api/v1/messages 11 | 12 | Lists all messages excluding message content 13 | 14 | ### DELETE /api/v1/messages 15 | 16 | Deletes all messages 17 | 18 | Returns a ```200``` response code if message deletion was successful. 19 | 20 | ### GET /api/v1/messages/{ message_id } 21 | 22 | Returns an individual message including message content 23 | 24 | ### DELETE /api/v1/messages/{ message_id } 25 | 26 | Delete an individual message 27 | 28 | Returns a ```200``` response code if message deletion was successful. 29 | 30 | ### GET /api/v1/messages/{ message_id }/download 31 | 32 | Download the complete message 33 | 34 | ### GET /api/v1/messages/{ message_id }/mime/part/{ part_index }/download 35 | 36 | Download a MIME part 37 | 38 | ### POST /api/v1/messages/{ message_id }/release 39 | 40 | Release the message to an SMTP server 41 | 42 | Send a JSON body specifying the recipient, SMTP hostname and port number: 43 | 44 | ```json 45 | { 46 | "Host": "mail.example.com", 47 | "Post": "25", 48 | "Email": "someone@example.com" 49 | } 50 | ``` 51 | 52 | Returns a ```200``` response code if message delivery was successful. 53 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=0.2.0 2 | 3 | all: deps fmt combined 4 | 5 | combined: 6 | go install . 7 | 8 | release: release-deps 9 | gox -output="build/{{.Dir}}_{{.OS}}_{{.Arch}}" . 10 | 11 | fmt: 12 | go fmt ./... 13 | 14 | deps: 15 | go get github.com/mailhog/MailHog-Server 16 | go get github.com/mailhog/MailHog-UI 17 | go get github.com/mailhog/mhsendmail 18 | cd ../MailHog-UI; make bindata 19 | go get github.com/mailhog/http 20 | go get github.com/ian-kent/go-log/log 21 | go get github.com/ian-kent/envconf 22 | go get github.com/ian-kent/goose 23 | go get github.com/ian-kent/linkio 24 | go get github.com/jteeuwen/go-bindata/... 25 | go get labix.org/v2/mgo 26 | # added to fix travis issues 27 | go get code.google.com/p/go-uuid/uuid 28 | go get golang.org/x/crypto/bcrypt 29 | 30 | test-deps: 31 | go get github.com/smartystreets/goconvey 32 | 33 | release-deps: 34 | go get github.com/mitchellh/gox 35 | 36 | pull: 37 | git pull 38 | cd ../data; git pull 39 | cd ../http; git pull 40 | cd ../MailHog-Server; git pull 41 | cd ../MailHog-UI; git pull 42 | cd ../smtp; git pull 43 | cd ../storage; git pull 44 | 45 | tag: 46 | git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 47 | cd ../data; git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 48 | cd ../http; git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 49 | cd ../MailHog-Server; git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 50 | cd ../MailHog-UI; git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 51 | cd ../smtp; git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 52 | cd ../storage; git tag -a -m 'v${VERSION}' ${VERSION} && git push origin ${VERSION} 53 | 54 | .PNONY: all combined release fmt deps test-deps release-deps 55 | -------------------------------------------------------------------------------- /docs/DEPLOY.md: -------------------------------------------------------------------------------- 1 | Deploying MailHog 2 | ================= 3 | 4 | ### Command line 5 | 6 | You can run MailHog locally from the command line. 7 | 8 | go get github.com/mailhog/MailHog 9 | MailHog -h 10 | 11 | To configure MailHog, use the environment variables or command line flags 12 | described in the [README](README.md). 13 | 14 | ### Using supervisord/upstart/etc 15 | 16 | MailHog can be started as a daemon using supervisord/upstart/etc. 17 | 18 | See [this example init script](https://github.com/geerlingguy/ansible-role-mailhog/blob/master/files/mailhog) 19 | and [this Ansible role](https://github.com/geerlingguy/ansible-role-mailhog) by [geerlingguy](https://github.com/geerlingguy). 20 | 21 | ### Docker 22 | 23 | The example [Dockerfile](Dockerfile) can be used to run MailHog in a [Docker](https://www.docker.com/) container. 24 | 25 | You can run it directly from Docker Hub (thanks [humboldtux](https://github.com/humboldtux)) 26 | 27 | docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog 28 | 29 | ### Elastic Beanstalk 30 | 31 | You can deploy MailHog using [AWS Elastic Beanstalk](http://aws.amazon.com/elasticbeanstalk/). 32 | 33 | 1. Open the Elastic Beanstalk console 34 | 2. Create a zip file containing the Dockerfile and MailHog binary 35 | 3. Create a new Elastic Beanstalk application 36 | 4. Launch a new environment and upload the zip file 37 | 38 | **Note** You'll need to reconfigure nginx in Elastic Beanstalk to expose both 39 | ports as TCP, since by default it proxies the first exposed port to port 80 as HTTP. 40 | 41 | If you're using in-memory storage, you can only use a single instance of 42 | MailHog. To use a load balanced EB application, use MongoDB backed storage. 43 | 44 | To configure your Elastic Beanstalk MailHog instance, either: 45 | 46 | * Set environment variables using the Elastic Beanstalk console 47 | * Edit the Dockerfile to pass in command line arguments 48 | 49 | You may face restrictions on outbound SMTP from EC2, for example if you are 50 | releasing messages to real SMTP servers. 51 | -------------------------------------------------------------------------------- /docs/JIM.md: -------------------------------------------------------------------------------- 1 | Introduction to Jim 2 | =================== 3 | 4 | Jim is the MailHog Chaos Monkey, inspired by Netflix. 5 | 6 | You can invite Jim to the party using the `invite-jim` flag: 7 | 8 | MailHog -invite-jim 9 | 10 | With Jim around, things aren't going to work how you expect. 11 | 12 | ### What can Jim do? 13 | 14 | * Reject connections 15 | * Rate limit connections 16 | * Reject authentication 17 | * Reject senders 18 | * Reject recipients 19 | 20 | It does this randomly, but within defined parameters. 21 | 22 | You can control these using the following command line flags: 23 | 24 | | Flag | Default | Description 25 | | --------------------- | ------- | ---- 26 | | -invite-jim | false | Set to true to invite Jim 27 | | -jim-disconnect | 0.005 | Chance of randomly disconnecting a session 28 | | -jim-accept | 0.99 | Chance of accepting an incoming connection 29 | | -jim-linkspeed-affect | 0.1 | Chance of applying a rate limit 30 | | -jim-linkspeed-min | 1024 | Minimum link speed (in bytes per second) 31 | | -jim-linkspeed-max | 10240 | Maximum link speed (in bytes per second) 32 | | -jim-reject-sender | 0.05 | Chance of rejecting a MAIL FROM command 33 | | -jim-reject-recipient | 0.05 | Chance of rejecting a RCPT TO command 34 | | -jim-reject-auth | 0.05 | Chance of rejecting an AUTH command 35 | 36 | If you enable Jim, you enable all parts. To disable individual parts, set the chance 37 | of it happening to 0, e.g. to disable connection rate limiting: 38 | 39 | MailHog -invite-jim -jim-linkspeed-affect=0 40 | 41 | ### Examples 42 | 43 | Always rate limit to 1 byte per second: 44 | 45 | MailHog -invite-jim -jim-linkspeed-affect=1 -jim-linkspeed-max=1 -jim-linkspeed-min=1 46 | 47 | Disconnect clients after approximately 5 commands: 48 | 49 | MailHog -invite-jim -jim-disconnect=0.2 50 | 51 | Simulate a mobile connection (at 10-100kbps) for 10% of clients: 52 | 53 | MailHog -invite-jim -jim-linkspeed-affect=0.1 -jim-linkspeed-min=1250 -jim-linkspeed-max=12500 54 | -------------------------------------------------------------------------------- /docs/CONFIG.md: -------------------------------------------------------------------------------- 1 | Configuring MailHog 2 | =================== 3 | 4 | You can configure MailHog using command line options or environment variables: 5 | 6 | | Environment | Command line | Default | Description 7 | | ------------------- | --------------- | --------------- | ----------- 8 | | MH_CORS_ORIGIN | -cors-origin | | If set, a Access-Control-Allow-Origin header is returned for API endpoints 9 | | MH_HOSTNAME | -hostname | mailhog.example | Hostname to use for EHLO/HELO and message IDs 10 | | MH_API_BIND_ADDR | -api-bind-addr | 0.0.0.0:8025 | Interface and port for HTTP UI server to bind to 11 | | MH_UI_BIND_ADDR | -ui-bind-addr | 0.0.0.0:8025 | Interface and port for HTTP API server to bind to 12 | | MH_MONGO_COLLECTION | -mongo-coll | messages | MongoDB collection name for message storage 13 | | MH_MONGO_DB | -mongo-db | mailhog | MongoDB database name for message storage 14 | | MH_MONGO_URI | -mongo-uri | 127.0.0.1:27017 | MongoDB host and port 15 | | MH_SMTP_BIND_ADDR | -smtp-bind-addr | 0.0.0.0:1025 | Interface and port for SMTP server to bind to 16 | | MH_STORAGE | -storage | memory | Set message storage: memory / mongodb 17 | | MH_OUTGOING_SMTP | -outgoing-smtp | | JSON file defining outgoing SMTP servers 18 | 19 | #### Note on HTTP bind addresses 20 | 21 | If `api-bind-addr` and `ui-bind-addr` are identical, a single listener will 22 | be used allowing both to co-exist on one port. 23 | 24 | The values must match in a string comparison. Resolving to the same host and 25 | port combination isn't enough. 26 | 27 | ### Outgoing SMTP configuration 28 | 29 | Outgoing SMTP servers can be set in web UI when releasing a message, and can 30 | be temporarily persisted for later use in the same session. 31 | 32 | To make outgoing SMTP servers permanently available, create a JSON file with 33 | the following structure, and set `MH_OUTGOING_SMTP` or `-outgoing-smtp`. 34 | 35 | ```json 36 | { 37 | "server name": { 38 | "name": "server name", 39 | "host": "...", 40 | "port": "587", 41 | "email": "...", 42 | "username": "...", 43 | "password": "...", 44 | "mechanism": "PLAIN" 45 | } 46 | } 47 | ``` 48 | 49 | Only `name`, `host` and `port` are required. 50 | 51 | `mechanism` can be `PLAIN` or `CRAM-MD5`. 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MailHog [ ![Download](https://img.shields.io/github/release/mailhog/MailHog.svg) ](https://github.com/mailhog/MailHog/releases/tag/v0.1.7) [![GoDoc](https://godoc.org/github.com/mailhog/MailHog?status.svg)](https://godoc.org/github.com/mailhog/MailHog) [![Build Status](https://travis-ci.org/mailhog/MailHog.svg?branch=master)](https://travis-ci.org/mailhog/MailHog) 2 | ========= 3 | 4 | Inspired by [MailCatcher](http://mailcatcher.me/), easier to install. 5 | 6 | * Download and run MailHog 7 | * Configure your outgoing SMTP server 8 | * View your outgoing email in a web UI 9 | * Release it to a real mail server 10 | 11 | Built with Go - MailHog runs without installation on multiple platforms. 12 | 13 | ### Overview 14 | 15 | MailHog is an email testing tool for developers: 16 | 17 | * Configure your application to use MailHog for SMTP delivery 18 | * View messages in the web UI, or retrieve them with the JSON API 19 | * Optionally release messages to real SMTP servers for delivery 20 | 21 | ### Getting started 22 | 23 | 1. Either: 24 | * [Download the latest release](/docs/RELEASES.md) of MailHog for your platform 25 | * [Run it from Docker Hub](https://registry.hub.docker.com/u/mailhog/mailhog/) or using the provided [Dockerfile](Dockerfile) 26 | * [Read the deployment guide](/docs/DEPLOY.md) for other deployment options 27 | 2. [Configure MailHog](/docs/CONFIG.md), or use the default settings: 28 | * the SMTP server starts on port 1025 29 | * the HTTP server starts on port 8025 30 | * in-memory message storage 31 | 32 | ### Features 33 | 34 | * ESMTP server implementing RFC5321 35 | * Support for SMTP AUTH (RFC4954) and PIPELINING (RFC2920) 36 | * Web interface to view messages (plain text, HTML or source) 37 | * Supports RFC2047 encoded headers 38 | * Real-time updates using EventSource 39 | * Release messages to real SMTP servers 40 | * Chaos Monkey for failure testing 41 | * See [Introduction to Jim](/docs/JIM.md) for more information 42 | * HTTP API to list, retrieve and delete messages 43 | * See [APIv1](/docs/APIv1.md) and [APIv2](/docs/APIv2.md) documentation for more information 44 | * [HTTP basic authentication](docs/Auth.md) for MailHog UI and API 45 | * Multipart MIME support 46 | * Download individual MIME parts 47 | * In-memory message storage 48 | * MongoDB storage for message persistence 49 | * Lightweight and portable 50 | * No installation required 51 | 52 | #### sendmail 53 | 54 | [mhsendmail](https://github.com/mailhog/mhsendmail) is a sendmail replacement for MailHog. 55 | 56 | It redirects mail to MailHog using SMTP. 57 | 58 | You can also use `MailHog sendmail ...` instead of the separate mhsendmail binary. 59 | 60 | #### Web UI 61 | 62 | ![Screenshot of MailHog web interface](/docs/MailHog.png "MailHog web interface") 63 | 64 | ### Contributing 65 | 66 | MailHog is a rewritten version of [MailHog](https://github.com/ian-kent/MailHog), which was born out of [M3MTA](https://github.com/ian-kent/M3MTA). 67 | 68 | Clone this repository to ```$GOPATH/src/github.com/mailhog/MailHog``` and type ```make deps```. 69 | 70 | See the [Building MailHog](/docs/BUILD.md) guide. 71 | 72 | Requires Go 1.4+ to build. 73 | 74 | Run tests using ```make test``` or ```goconvey```. 75 | 76 | If you make any changes, run ```go fmt ./...``` before submitting a pull request. 77 | 78 | ### Licence 79 | 80 | Copyright ©‎ 2014-2015, Ian Kent (http://iankent.uk) 81 | 82 | Released under MIT license, see [LICENSE](LICENSE.md) for details. 83 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | gohttp "net/http" 9 | 10 | "github.com/gorilla/pat" 11 | "github.com/ian-kent/go-log/log" 12 | "github.com/mailhog/MailHog-Server/api" 13 | cfgapi "github.com/mailhog/MailHog-Server/config" 14 | "github.com/mailhog/MailHog-Server/smtp" 15 | "github.com/mailhog/MailHog-UI/assets" 16 | cfgui "github.com/mailhog/MailHog-UI/config" 17 | "github.com/mailhog/MailHog-UI/web" 18 | cfgcom "github.com/mailhog/MailHog/config" 19 | "github.com/mailhog/http" 20 | "github.com/mailhog/mhsendmail/cmd" 21 | "golang.org/x/crypto/bcrypt" 22 | ) 23 | 24 | var apiconf *cfgapi.Config 25 | var uiconf *cfgui.Config 26 | var comconf *cfgcom.Config 27 | var exitCh chan int 28 | 29 | func configure() { 30 | cfgcom.RegisterFlags() 31 | cfgapi.RegisterFlags() 32 | cfgui.RegisterFlags() 33 | flag.Parse() 34 | apiconf = cfgapi.Configure() 35 | uiconf = cfgui.Configure() 36 | comconf = cfgcom.Configure() 37 | } 38 | 39 | func main() { 40 | if len(os.Args) > 1 && os.Args[1] == "sendmail" { 41 | args := os.Args 42 | os.Args = []string{args[0]} 43 | if len(args) > 2 { 44 | os.Args = append(os.Args, args[2:]...) 45 | } 46 | cmd.Go() 47 | return 48 | } 49 | 50 | if len(os.Args) > 1 && os.Args[1] == "bcrypt" { 51 | var pw string 52 | if len(os.Args) > 2 { 53 | pw = os.Args[2] 54 | } else { 55 | // TODO: read from stdin 56 | } 57 | b, err := bcrypt.GenerateFromPassword([]byte(pw), 4) 58 | if err != nil { 59 | log.Fatalf("error bcrypting password: %s", err) 60 | os.Exit(1) 61 | } 62 | fmt.Println(string(b)) 63 | os.Exit(0) 64 | } 65 | 66 | configure() 67 | 68 | if comconf.AuthFile != "" { 69 | http.AuthFile(comconf.AuthFile) 70 | } 71 | 72 | exitCh = make(chan int) 73 | if uiconf.UIBindAddr == apiconf.APIBindAddr { 74 | cb := func(r gohttp.Handler) { 75 | web.CreateWeb(uiconf, r.(*pat.Router), assets.Asset) 76 | api.CreateAPIv1(apiconf, r.(*pat.Router)) 77 | api.CreateAPIv2(apiconf, r.(*pat.Router)) 78 | } 79 | go http.Listen(uiconf.UIBindAddr, assets.Asset, exitCh, cb) 80 | } else { 81 | cb1 := func(r gohttp.Handler) { 82 | api.CreateAPIv1(apiconf, r.(*pat.Router)) 83 | api.CreateAPIv2(apiconf, r.(*pat.Router)) 84 | } 85 | cb2 := func(r gohttp.Handler) { 86 | web.CreateWeb(uiconf, r.(*pat.Router), assets.Asset) 87 | } 88 | go http.Listen(apiconf.APIBindAddr, assets.Asset, exitCh, cb1) 89 | go http.Listen(uiconf.UIBindAddr, assets.Asset, exitCh, cb2) 90 | } 91 | go smtp.Listen(apiconf, exitCh) 92 | 93 | for { 94 | select { 95 | case <-exitCh: 96 | log.Printf("Received exit signal") 97 | os.Exit(0) 98 | } 99 | } 100 | } 101 | 102 | /* 103 | 104 | Add some random content to the end of this file, hopefully tricking GitHub 105 | into recognising this as a Go repo instead of Makefile. 106 | 107 | A gopher, ASCII art style - borrowed from 108 | https://gist.github.com/belbomemo/b5e7dad10fa567a5fe8a 109 | 110 | ,_---~~~~~----._ 111 | _,,_,*^____ _____``*g*\"*, 112 | / __/ /' ^. / \ ^@q f 113 | [ @f | @)) | | @)) l 0 _/ 114 | \`/ \~____ / __ \_____/ \ 115 | | _l__l_ I 116 | } [______] I 117 | ] | | | | 118 | ] ~ ~ | 119 | | | 120 | | | 121 | 122 | */ 123 | -------------------------------------------------------------------------------- /docs/RELEASES.md: -------------------------------------------------------------------------------- 1 | MailHog Releases 2 | ================ 3 | 4 | ### [v0.1.7](https://github.com/mailhog/MailHog/releases/v0.1.7) 5 | - Add [mhsendmail](https://github.com/mailhog/mhsendmail) sendmail replacement 6 | - Fix #42 - panic when setting UI bind address 7 | - Fix #46 - utf8 error in e-mail subject 8 | - Fix #41 and #50 - underscores replaced with spaces in UI 9 | - Fix mailhog/MailHog-UI#6 - user defined pagination 10 | - Merge #43 and #44 - fix documentation, thanks @eirc 11 | - Merge #48 - fix documentation, thanks @zhubert 12 | - Merge mailhog/MailHog-Server#1 - avoid duplicate headers, thanks @wienczny 13 | 14 | ### [v0.1.6](https://github.com/mailhog/MailHog/releases/v0.1.6) 15 | - Fix #24 - base64 attachments/mime part downloads 16 | - Fix #28 - embed js/css/font assets for offline use 17 | - Fix #29 - overview of MailHog for readme 18 | - Fix #34 - message list scrolling 19 | - Fix #35 - message list sorting 20 | - Fix #36 - document outgoing SMTP server configuration and APIv2 21 | - Merge mailhog/MailHog-UI#4 - support base64 content transfer encoding, thanks @stekershaw 22 | - Merge mailhog/Mailhog-UI#5 - single part encoded text/plain, thanks @naoina 23 | 24 | ### [v0.1.5](https://github.com/mailhog/MailHog/releases/v0.1.5) 25 | - Fix mailhog/MailHog-UI#3 - squashed subject line 26 | 27 | ### [v0.1.4](https://github.com/mailhog/MailHog/releases/v0.1.4) 28 | - Merge mailhog/data#2 - MIME boundary fixes, thanks @nvcnvn 29 | - Merge mailhog/MailHog-UI#2 - UI overhaul, thanks @omegahm 30 | - Fix #31 - updated this file :smile: 31 | 32 | ### [v0.1.3](https://github.com/mailhog/MailHog/releases/v0.1.3) 33 | - Fix #22 - render non-multipart messages with HTML content type 34 | - Fix #25 - make web UI resource paths relative 35 | 36 | ### [v0.1.2](https://github.com/mailhog/MailHog/releases/v0.1.2) 37 | - Hopefully fix #22 - broken rendering of HTML email 38 | - Partially implement #15 - authentication for SMTP release 39 | - Load outgoing SMTP servers from file 40 | - Save outgoing SMTP server when releasing message in UI 41 | - Select outgoing SMTP server when release message in UI 42 | - Make Jim (Chaos Monkey) available via APIv2 43 | - Add Jim overview and on/off switch to web UI 44 | 45 | ### [v0.1.1](https://github.com/mailhog/MailHog/releases/v0.1.1) 46 | - Fix #23 - switch to iframe to fix CSS bug 47 | - Update to latest AngularJS 48 | - Update Dockerfile - thanks @humboldtux 49 | - Fix SMTP AUTH bug (missing from EHLO) 50 | - Fix SMTP new line parsing 51 | 52 | ### [v0.1.0](https://github.com/mailhog/MailHog/releases/v0.1.0) 53 | 54 | - Switch to semantic versioning 55 | - Rewrite web user interface 56 | - Deprecate APIv1 57 | - Rewrite messages endpoint for APIv2 58 | - Add search to APIv2 59 | 60 | ### [v0.09](https://github.com/mailhog/MailHog/releases/0.08) 61 | 62 | - Fix #8 - add Chaos Monkey ([Jim](JIM.md)) to support failure testing 63 | 64 | ### [v0.08](https://github.com/mailhog/MailHog/releases/0.08) 65 | 66 | - Extract SMTP protocol into isolated library 67 | - Better protocol tests 68 | - Add hooks for manipulating protocol behaviour 69 | - Merge #14 - fix display of multipart messges, thanks @derwassi 70 | - Merge #17 - fix API v1 docs, thanks @geerlingguy 71 | - Fix #11 - add build documentation 72 | - Fix #12 - support broken MAIL/RCPT syntax 73 | - Fix #16 - add deployment documentation 74 | - Fix #18 - better server-sent event support using [goose](https://github.com/ian-kent/goose) 75 | 76 | ### [v0.07](https://github.com/mailhog/MailHog/releases/tag/0.07) 77 | 78 | - Fix #6 - Make SMTP verbs case-insensitive 79 | 80 | ### [v0.06](https://github.com/mailhog/MailHog/releases/tag/0.06) 81 | 82 | - Fix #5 - Support leading tab in multiline headers 83 | 84 | ### [v0.05](https://github.com/mailhog/MailHog/releases/tag/0.05) 85 | 86 | - Add #4 - UI support for RFC2047 encoded headers 87 | 88 | ### [v0.04](https://github.com/mailhog/MailHog/releases/tag/0.04) 89 | 90 | * Configure from environment 91 | * Include example Dockerfile 92 | * Fix #1 - mismatched import path and repository name 93 | * Fix #2 - possible panic with some MIME content 94 | * Fix #3 - incorrect handling of RSET 95 | 96 | 97 | ### [v0.03](https://github.com/mailhog/MailHog/releases/tag/0.03) 98 | 99 | * Download message in .eml format 100 | * Cleaned up v1 API 101 | * Web UI and API improvements 102 | * Fixed UI rendering bugs 103 | * Message search and matched/total message count 104 | * Message list resizing and scrolling 105 | * EventSource support for message streaming 106 | * Better error handling and reporting 107 | * View/download individual MIME parts 108 | * Release messages to real SMTP servers 109 | * Switch to [go-bindata](https://github.com/jteeuwen/go-bindata) for asset embedding 110 | 111 | ### [v0.02](https://github.com/mailhog/MailHog/releases/tag/0.02) 112 | 113 | * Better support for ESMTP (RFC5321) 114 | * Support for SMTP AUTH (RFC4954) and PIPELINING (RFC2920) 115 | * Improved AJAX web interface to view messages (plain text, HTML or source) 116 | * Improved HTTP API to list, retrieve and delete messages 117 | * Multipart MIME support 118 | * In-memory message storage 119 | * MongoDB storage for message persistence 120 | 121 | ### [v0.01](https://github.com/mailhog/MailHog/releases/tag/0.01) 122 | 123 | * Basic support for SMTP and HTTP servers 124 | * Accepts SMTP messages 125 | * Stores parsed messages in MongoDB 126 | * Makes messages available via API 127 | * has Bootstrap/AngularJS UI for viewing/deleting messages 128 | -------------------------------------------------------------------------------- /docs/APIv2/swagger-2.0.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | 3 | info: 4 | version: "2.0.0" 5 | title: MailHog API 6 | 7 | paths: 8 | /api/v2/messages: 9 | get: 10 | description: | 11 | Retrieve a list of messages 12 | parameters: 13 | - 14 | name: start 15 | in: query 16 | description: Start index 17 | required: false 18 | type: number 19 | format: int64 20 | default: 0 21 | - 22 | name: limit 23 | in: query 24 | description: Number of messages 25 | required: false 26 | type: number 27 | format: int64 28 | default: 50 29 | responses: 30 | 200: 31 | description: Successful response 32 | schema: 33 | title: Messages 34 | type: object 35 | properties: 36 | total: 37 | type: number 38 | format: int64 39 | description: Total number of stored messages 40 | start: 41 | type: number 42 | format: int64 43 | description: Start index of first returned message 44 | count: 45 | type: number 46 | format: int64 47 | description: Number of returned messages 48 | messages: 49 | type: array 50 | items: 51 | title: Message 52 | type: object 53 | properties: 54 | id: 55 | type: string 56 | from: 57 | title: Path 58 | type: object 59 | properties: 60 | relays: 61 | type: array 62 | items: 63 | type: string 64 | mailbox: 65 | type: string 66 | domain: 67 | type: string 68 | params: 69 | type: string 70 | to: 71 | type: array 72 | items: 73 | title: Path 74 | type: object 75 | properties: 76 | relays: 77 | type: array 78 | items: 79 | type: string 80 | mailbox: 81 | type: string 82 | domain: 83 | type: string 84 | params: 85 | type: string 86 | headers: 87 | type: object 88 | size: 89 | type: number 90 | format: int64 91 | created: 92 | type: string 93 | format: date-time 94 | /api/v2/search: 95 | get: 96 | description: | 97 | Search messages 98 | parameters: 99 | - 100 | name: kind 101 | in: query 102 | description: Kind of search 103 | required: true 104 | type: string 105 | enum: [ from, to, containing ] 106 | - 107 | name: start 108 | in: query 109 | description: Start index 110 | required: false 111 | type: number 112 | format: int64 113 | default: 0 114 | - 115 | name: limit 116 | in: query 117 | description: Number of messages 118 | required: false 119 | type: number 120 | format: int64 121 | default: 50 122 | responses: 123 | 200: 124 | description: Successful response 125 | schema: 126 | title: Messages 127 | type: object 128 | properties: 129 | total: 130 | type: number 131 | format: int64 132 | description: Total number of stored messages 133 | start: 134 | type: number 135 | format: int64 136 | description: Start index of first returned message 137 | count: 138 | type: number 139 | format: int64 140 | description: Number of returned messages 141 | messages: 142 | type: array 143 | items: 144 | title: Message 145 | type: object 146 | properties: 147 | id: 148 | type: string 149 | from: 150 | title: Path 151 | type: object 152 | properties: 153 | relays: 154 | type: array 155 | items: 156 | type: string 157 | mailbox: 158 | type: string 159 | domain: 160 | type: string 161 | params: 162 | type: string 163 | to: 164 | type: array 165 | items: 166 | title: Path 167 | type: object 168 | properties: 169 | relays: 170 | type: array 171 | items: 172 | type: string 173 | mailbox: 174 | type: string 175 | domain: 176 | type: string 177 | params: 178 | type: string 179 | headers: 180 | type: object 181 | size: 182 | type: number 183 | format: int64 184 | created: 185 | type: string 186 | format: date-time -------------------------------------------------------------------------------- /docs/APIv2/swagger-2.0.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "version": "2.0.0", 5 | "title": "MailHog API" 6 | }, 7 | "paths": { 8 | "/api/v2/messages": { 9 | "get": { 10 | "description": "Retrieve a list of messages\n", 11 | "parameters": [ 12 | { 13 | "name": "start", 14 | "in": "query", 15 | "description": "Start index", 16 | "required": false, 17 | "type": "number", 18 | "format": "int64", 19 | "default": 0 20 | }, 21 | { 22 | "name": "limit", 23 | "in": "query", 24 | "description": "Number of messages", 25 | "required": false, 26 | "type": "number", 27 | "format": "int64", 28 | "default": 50 29 | } 30 | ], 31 | "responses": { 32 | "200": { 33 | "description": "Successful response", 34 | "schema": { 35 | "title": "Messages", 36 | "type": "object", 37 | "properties": { 38 | "total": { 39 | "type": "number", 40 | "format": "int64", 41 | "description": "Total number of stored messages" 42 | }, 43 | "start": { 44 | "type": "number", 45 | "format": "int64", 46 | "description": "Start index of first returned message" 47 | }, 48 | "count": { 49 | "type": "number", 50 | "format": "int64", 51 | "description": "Number of returned messages" 52 | }, 53 | "messages": { 54 | "type": "array", 55 | "items": { 56 | "title": "Message", 57 | "type": "object", 58 | "properties": { 59 | "id": { 60 | "type": "string" 61 | }, 62 | "from": { 63 | "title": "Path", 64 | "type": "object", 65 | "properties": { 66 | "relays": { 67 | "type": "array", 68 | "items": { 69 | "type": "string" 70 | } 71 | }, 72 | "mailbox": { 73 | "type": "string" 74 | }, 75 | "domain": { 76 | "type": "string" 77 | }, 78 | "params": { 79 | "type": "string" 80 | } 81 | } 82 | }, 83 | "to": { 84 | "type": "array", 85 | "items": { 86 | "title": "Path", 87 | "type": "object", 88 | "properties": { 89 | "relays": { 90 | "type": "array", 91 | "items": { 92 | "type": "string" 93 | } 94 | }, 95 | "mailbox": { 96 | "type": "string" 97 | }, 98 | "domain": { 99 | "type": "string" 100 | }, 101 | "params": { 102 | "type": "string" 103 | } 104 | } 105 | } 106 | }, 107 | "headers": { 108 | "type": "object" 109 | }, 110 | "size": { 111 | "type": "number", 112 | "format": "int64" 113 | }, 114 | "created": { 115 | "type": "string", 116 | "format": "date-time" 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | }, 127 | "/api/v2/search": { 128 | "get": { 129 | "description": "Search messages\n", 130 | "parameters": [ 131 | { 132 | "name": "kind", 133 | "in": "query", 134 | "description": "Kind of search", 135 | "required": true, 136 | "type": "string", 137 | "enum": [ 138 | "from", 139 | "to", 140 | "containing" 141 | ] 142 | }, 143 | { 144 | "name": "start", 145 | "in": "query", 146 | "description": "Start index", 147 | "required": false, 148 | "type": "number", 149 | "format": "int64", 150 | "default": 0 151 | }, 152 | { 153 | "name": "limit", 154 | "in": "query", 155 | "description": "Number of messages", 156 | "required": false, 157 | "type": "number", 158 | "format": "int64", 159 | "default": 50 160 | } 161 | ], 162 | "responses": { 163 | "200": { 164 | "description": "Successful response", 165 | "schema": { 166 | "title": "Messages", 167 | "type": "object", 168 | "properties": { 169 | "total": { 170 | "type": "number", 171 | "format": "int64", 172 | "description": "Total number of stored messages" 173 | }, 174 | "start": { 175 | "type": "number", 176 | "format": "int64", 177 | "description": "Start index of first returned message" 178 | }, 179 | "count": { 180 | "type": "number", 181 | "format": "int64", 182 | "description": "Number of returned messages" 183 | }, 184 | "messages": { 185 | "type": "array", 186 | "items": { 187 | "title": "Message", 188 | "type": "object", 189 | "properties": { 190 | "id": { 191 | "type": "string" 192 | }, 193 | "from": { 194 | "title": "Path", 195 | "type": "object", 196 | "properties": { 197 | "relays": { 198 | "type": "array", 199 | "items": { 200 | "type": "string" 201 | } 202 | }, 203 | "mailbox": { 204 | "type": "string" 205 | }, 206 | "domain": { 207 | "type": "string" 208 | }, 209 | "params": { 210 | "type": "string" 211 | } 212 | } 213 | }, 214 | "to": { 215 | "type": "array", 216 | "items": { 217 | "title": "Path", 218 | "type": "object", 219 | "properties": { 220 | "relays": { 221 | "type": "array", 222 | "items": { 223 | "type": "string" 224 | } 225 | }, 226 | "mailbox": { 227 | "type": "string" 228 | }, 229 | "domain": { 230 | "type": "string" 231 | }, 232 | "params": { 233 | "type": "string" 234 | } 235 | } 236 | } 237 | }, 238 | "headers": { 239 | "type": "object" 240 | }, 241 | "size": { 242 | "type": "number", 243 | "format": "int64" 244 | }, 245 | "created": { 246 | "type": "string", 247 | "format": "date-time" 248 | } 249 | } 250 | } 251 | } 252 | } 253 | } 254 | } 255 | } 256 | } 257 | } 258 | } 259 | } --------------------------------------------------------------------------------