Last active
December 26, 2015 13:48
-
-
Save dtjm/7160539 to your computer and use it in GitHub Desktop.
SendGrid cover letter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html> | |
| <head> | |
| <meta charset='utf-8'> | |
| <title>EHLO SendGrid</title> | |
| <style type="text/css"> | |
| body { | |
| background-color: #eee; | |
| color: #222; | |
| font-family: "Courier", monospace; | |
| font-size: 16px; | |
| margin: 0; | |
| padding: 40px 0;f | |
| } | |
| body > p { | |
| margin: 1em 40px; | |
| width: 600px; | |
| } | |
| .scroller { | |
| background: #111; | |
| box-shadow: 0 4px 20px black; | |
| height: 400px; | |
| overflow: auto; | |
| margin: 2em 0; | |
| min-width: 800px; | |
| max-width: 90%; | |
| } | |
| .scroller:-webkit-full-screen { | |
| background: black; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .tx { | |
| color: green; | |
| float: left; | |
| overflow-x: hidden; | |
| padding: 10px; | |
| min-width: 380px; | |
| width: 47% | |
| } | |
| #recv { | |
| color: orange; | |
| } | |
| div.log { | |
| overflow-x: auto; | |
| } | |
| div.log div { | |
| border-top: 1px dotted #040; | |
| font-size: 13px; | |
| height: 13px; | |
| padding: 5px 0; | |
| margin-top: 5px; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <p><em>Send an email to | |
| <strong>test@sendgrid.autumncloud.net</strong> and watch the | |
| action here.</em> (Works best in Chrome or Safari)</p> | |
| <p><a href="#" class="fullscreen">Enter full screen</a></p> | |
| <div class="scroller"> | |
| <div class="tx" id="send"> | |
| <strong>SEND</strong> | |
| <div class="log"> | |
| </div> | |
| </div> | |
| <div class="tx" id="recv"> | |
| <strong>RECV</strong> | |
| <div class="log"> | |
| </div> | |
| </div> | |
| </div> | |
| <p> | |
| <a href="/main.go">SMTP-to-HTML server source code</a> | |
| </p> | |
| <script> | |
| var blink = function(selector) { | |
| var el = document.querySelector(selector); | |
| var oldVisibility = el.style.visibility; | |
| var intervalID = setInterval(function(){ | |
| if (el.style.visibility !== 'hidden') { | |
| el.style.visibility = 'hidden'; | |
| } else { | |
| el.style.visibility = oldVisibility; | |
| } | |
| }, 50); | |
| setTimeout(function(){ | |
| clearInterval(intervalID); | |
| el.style.visibility = oldVisibility; | |
| }, 500); | |
| }; | |
| var fullscreen = function() { | |
| var scroller = document.querySelector('.scroller'); | |
| if (scroller.webkitRequestFullscreen) { | |
| scroller.webkitRequestFullscreen(); | |
| } | |
| if (scroller.mozRequestFullScreen) { | |
| scroller.mozRequestFullScreen(); | |
| } | |
| }; | |
| var fsEl = document.querySelector("a.fullscreen"); | |
| fsEl.addEventListener("click", function(){ | |
| fullscreen(); | |
| return false; | |
| }); | |
| var log = function(elId, msg) { | |
| var parent = document.getElementById(elId); | |
| var logEl = parent.querySelector('.log'); | |
| var entry = document.createElement('div'); | |
| entry.textContent = msg; | |
| logEl.appendChild(entry); | |
| }; | |
| var scrollToBottom = function() { | |
| var scroller = document.querySelector('.scroller'); | |
| scroller.scrollTop = scroller.scrollHeight; | |
| }; | |
| var sendHandler = function(e) { | |
| blink("#send strong"); | |
| log("send", e.data); | |
| log("recv", ""); | |
| scrollToBottom(); | |
| }; | |
| var recvHandler = function(e) { | |
| blink("#recv strong"); | |
| log("send", ""); | |
| log("recv", e.data); | |
| scrollToBottom(); | |
| }; | |
| var eventSource = new EventSource('/eventstream'); | |
| eventSource.addEventListener('send', sendHandler, false); | |
| eventSource.addEventListener('recv', recvHandler, false); | |
| blink("#recv strong"); | |
| blink("#send strong"); | |
| </script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "bufio" | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "log" | |
| "net" | |
| "time" | |
| ) | |
| var domain string = "sendgrid.autumncloud.net" | |
| var connID int = 0 | |
| var writers []http.ResponseWriter | |
| var quitters []chan bool | |
| type envelope struct { | |
| greeted bool | |
| receivingData bool | |
| connID int | |
| conn net.Conn | |
| reader *bufio.Reader | |
| } | |
| func checkErr(err error, conn net.Conn) { | |
| if netErr, ok := err.(net.Error); ok && netErr.Timeout() && conn != nil { | |
| fmt.Fprintf(conn, "QUIT sendgrid.autumncloud.net Timeout: %v\r\n", err.Error()) | |
| conn.Close() | |
| } | |
| if err != nil { | |
| log.Printf("%v", err) | |
| } | |
| } | |
| func timeout(conn net.Conn, duration time.Duration) { | |
| conn.SetDeadline(time.Now().Add(duration)) | |
| } | |
| func handleConn(conn net.Conn) { | |
| log.Printf("==%d: Accepted connection from %v", connID, conn.RemoteAddr()) | |
| e := envelope{ | |
| false, | |
| false, | |
| connID, | |
| conn, | |
| bufio.NewReader(conn), | |
| } | |
| // Send opening greeting | |
| greeting := fmt.Sprintf("220 %s SMTP", domain) | |
| e.send(greeting) | |
| for !e.greeted { | |
| err := e.handleHELO() | |
| if err != nil { | |
| log.Printf("E:%d: %s", e.connID, err.Error()) | |
| return | |
| } | |
| } | |
| for { | |
| err := e.handleNextLine() | |
| if err != nil { | |
| log.Printf("E:%d: %s", e.connID, err.Error()) | |
| return | |
| } | |
| } | |
| } | |
| func (e *envelope) handleNextLine() error { | |
| line, err := e.reader.ReadString('\n') | |
| if err != nil { | |
| return err | |
| } | |
| e.logRecv(line) | |
| if !e.receivingData && len(line) < 4 { | |
| fmt.Fprintf(e.conn, "500 Syntax error, command unrecognized\r\n") | |
| e.logSend("500 Syntax error, command unrecognized") | |
| return nil | |
| } | |
| if !e.receivingData && len(line) >= 4 && line[:4] == "HELP" { | |
| e.send("214-Hello SendGrid!") | |
| e.send("214-For more information about this server") | |
| e.send("214 go to http://sendgrid.autumncloud.net") | |
| return nil | |
| } | |
| if !e.receivingData && len(line) >= 4 && line[:4] == "DATA" { | |
| e.receivingData = true | |
| log.Printf("==%d: Receiving data", e.connID) | |
| e.send("354 Start mail input; end with <CRLF>.<CRLF>") | |
| return nil | |
| } | |
| if !e.receivingData && len(line) >= 4 && line[:4] == "QUIT" { | |
| e.conn.Close() | |
| log.Printf("==%d: Closing connection", e.connID) | |
| return io.EOF | |
| } | |
| if e.receivingData && line == ".\r\n" { | |
| e.receivingData = false | |
| log.Printf("==%d: Data block end", e.connID) | |
| } | |
| if !e.receivingData { | |
| e.send("250 OK") | |
| } | |
| return nil | |
| } | |
| func (e *envelope) handleHELO() error { | |
| // Get next line | |
| // timeout(e.conn, 0) | |
| line, err := e.reader.ReadString('\n') | |
| if err != nil { | |
| return err | |
| } | |
| // checkErr(err, e.conn) | |
| e.logRecv(line) | |
| if len(line) < 4 { | |
| e.send("500 Syntax error, command unrecognized") | |
| return nil | |
| } | |
| if line[:4] != "HELO" { | |
| e.send("500 Aren't you going to say HELO?") | |
| return nil | |
| } | |
| // HELO has been received, send 250 ACK | |
| e.send(fmt.Sprintf("250 %s", domain)) | |
| e.greeted = true | |
| return nil | |
| } | |
| func (e *envelope) logRecv(line string) { | |
| log.Printf("R:%d: %s", e.connID, line) | |
| writeEvent("recv", line) | |
| } | |
| func (e *envelope) logSend(line string) { | |
| log.Printf("S:%d: %s", e.connID, line) | |
| writeEvent("send", line) | |
| } | |
| func (e *envelope) send(line string) { | |
| fmt.Fprintf(e.conn, "%s\r\n", line) | |
| e.logSend(line) | |
| } | |
| func writeEvent(event, data string) { | |
| for i := 0; i < len(writers); i++ { | |
| w := writers[i] | |
| if w == nil { | |
| continue | |
| } | |
| _, err := fmt.Fprintf(w, "event: %s\ndata: %s\n\n", event, data) | |
| if err != nil { | |
| writers[i] = nil | |
| quitters[i] <- true | |
| } | |
| if flusher, ok := w.(http.Flusher); ok { | |
| flusher.Flush() | |
| } | |
| } | |
| } | |
| func main() { | |
| addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:25") | |
| checkErr(err, nil) | |
| l, err := net.ListenTCP("tcp", addr) | |
| if err != nil { | |
| log.Fatalf("Failed to listen on %v", addr) | |
| } | |
| log.Printf("Listening to smtp://%v", addr) | |
| writers = make([]http.ResponseWriter, 0, 0) | |
| quitters = make([]chan bool, 0, 0) | |
| http.HandleFunc("/eventstream", func(w http.ResponseWriter, r *http.Request) { | |
| log.Printf("Opening eventstream") | |
| w.Header().Set("Content-Type", "text/event-stream") | |
| writers = append(writers, w) | |
| quit := make(chan bool) | |
| quitters = append(quitters, quit) | |
| <-quit | |
| log.Printf("Closing eventstream") | |
| }) | |
| http.HandleFunc("/api/event_notification", func(w http.ResponseWriter, | |
| r *http.Request) { | |
| /*var b bytes.Buffer*/ | |
| log.Printf("===") | |
| log.Printf("=== INCOMING EVENT ===") | |
| log.Printf("%s %s %s", r.Method, r.RequestURI, r.Proto) | |
| /*r.Header.Write(&b)*/ | |
| r.ParseForm() | |
| for k, v := range r.Form { | |
| log.Printf("\t%s = %s", k, v) | |
| } | |
| /*log.Printf("%s", b.String())*/ | |
| /*s, _ := ioutil.ReadAll(r.Body)*/ | |
| /*log.Printf("%s", string(s))*/ | |
| }) | |
| go func() { | |
| log.Printf("Listening to http://127.0.0.1:5656") | |
| http.ListenAndServe("127.0.0.1:5656", nil) | |
| }() | |
| for { | |
| conn, err := l.AcceptTCP() | |
| if err != nil { | |
| log.Printf("AcceptTCP error: %s", err.Error()) | |
| } | |
| connID++ | |
| go handleConn(conn) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment