mirror of
https://github.com/hanzo-go/sendgrid.git
synced 2026-10-30 15:05:38 +00:00
216 lines
5.3 KiB
Go
216 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"mime"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/sendgrid/rest"
|
|
)
|
|
|
|
type configuration struct {
|
|
Endpoint string `json:"endpoint"`
|
|
Port string `json:"port"`
|
|
}
|
|
|
|
func loadConfig(path string) configuration {
|
|
file, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
log.Fatal("Config File Missing. ", err)
|
|
}
|
|
var conf configuration
|
|
err = json.Unmarshal(file, &conf)
|
|
if err != nil {
|
|
log.Fatal("Config Parse Error: ", err)
|
|
}
|
|
return conf
|
|
}
|
|
|
|
func indexHandler(response http.ResponseWriter, request *http.Request) {
|
|
fmt.Fprintf(response, "%s", "Hello World")
|
|
}
|
|
|
|
func getBoundary(value string, contentType string) (string, *strings.Reader) {
|
|
body := strings.NewReader(value)
|
|
bodySplit := strings.Split(string(value), contentType)
|
|
scanner := bufio.NewScanner(strings.NewReader(bodySplit[1]))
|
|
var lines []string
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
break
|
|
}
|
|
boundary := lines[0][9:]
|
|
return boundary, body
|
|
}
|
|
|
|
func inboundHandler(response http.ResponseWriter, request *http.Request) {
|
|
mediaType, params, err := mime.ParseMediaType(request.Header.Get("Content-Type"))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if strings.HasPrefix(mediaType, "multipart/") {
|
|
mr := multipart.NewReader(request.Body, params["boundary"])
|
|
parsedEmail := make(map[string]string)
|
|
emailHeader := make(map[string]string)
|
|
binaryFiles := make(map[string][]byte)
|
|
parsedRawEmail := make(map[string]string)
|
|
rawFiles := make(map[string]string)
|
|
for {
|
|
p, err := mr.NextPart()
|
|
// We have found an attachment with binary data
|
|
if err == nil && p.FileName() != "" {
|
|
contents, ioerr := ioutil.ReadAll(p)
|
|
if ioerr != nil {
|
|
log.Fatal(err)
|
|
}
|
|
binaryFiles[p.FileName()] = contents
|
|
}
|
|
if err == io.EOF {
|
|
// We have finished parsing, do something with the parsed data
|
|
printMap(parsedEmail, "")
|
|
printMap(emailHeader, "e")
|
|
|
|
for key, value := range binaryFiles {
|
|
fmt.Println("bKey:", key, " bValue:", value)
|
|
}
|
|
|
|
printMap(parsedRawEmail, "r")
|
|
printMap(rawFiles, "rf")
|
|
// SendGrid needs a 200 OK response to stop POSTing
|
|
response.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
value, err := ioutil.ReadAll(p)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
header := p.Header.Get("Content-Disposition")
|
|
if !strings.Contains(header, "filename") {
|
|
header = header[17 : len(header)-1]
|
|
parsedEmail[header] = string(value)
|
|
} else {
|
|
header = header[11:]
|
|
f := strings.Split(header, "=")
|
|
parsedEmail[f[1][1:len(f[1])-11]] = f[2][1 : len(f[2])-1]
|
|
}
|
|
|
|
if header == "headers" {
|
|
handleHeaders(value, emailHeader)
|
|
}
|
|
// Since we have parsed the headers, we can delete the original
|
|
delete(parsedEmail, "headers")
|
|
|
|
// We have a raw message
|
|
if header == "email" {
|
|
handleRawEmail(value, parsedRawEmail, rawFiles)
|
|
}
|
|
// Since we've parsed this header, we can delete the original
|
|
delete(parsedEmail, "email")
|
|
}
|
|
}
|
|
}
|
|
func handleHeaders(value []byte, emailHeader map[string]string) {
|
|
s := strings.Split(string(value), "\n")
|
|
var a []string
|
|
for _, v := range s {
|
|
t := strings.Split(string(v), ": ")
|
|
a = append(a, t...)
|
|
}
|
|
for i := 0; i < len(a)-1; i += 2 {
|
|
emailHeader[a[i]] = a[i+1]
|
|
}
|
|
}
|
|
|
|
func printMap(inputMap map[string]string, prefix string) {
|
|
for key, value := range inputMap {
|
|
fmt.Println(prefix, "Key:", key, " ", prefix, "Value:", value)
|
|
}
|
|
}
|
|
func handleRawEmail(value []byte, parsedRawEmail map[string]string, rawFiles map[string]string) {
|
|
boundary, body := getBoundary(string(value), "Content-Type: multipart/mixed; ")
|
|
raw := multipart.NewReader(body, boundary)
|
|
for {
|
|
next, err := raw.NextPart()
|
|
if err == io.EOF {
|
|
// We have finished parsing
|
|
break
|
|
}
|
|
value, err := ioutil.ReadAll(next)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
header := next.Header.Get("Content-Type")
|
|
|
|
// Parse the headers
|
|
if strings.Contains(header, "multipart/alternative") {
|
|
boundary, body := getBoundary(string(value), "Content-Type: multipart/alternative; ")
|
|
raw := multipart.NewReader(body, boundary)
|
|
for {
|
|
next, err := raw.NextPart()
|
|
if err == io.EOF {
|
|
// We have finished parsing
|
|
break
|
|
}
|
|
value, err = ioutil.ReadAll(next)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
header = next.Header.Get("Content-Type")
|
|
parsedRawEmail[header] = string(value)
|
|
}
|
|
} else {
|
|
// It's a base64 encoded attachment
|
|
rawFiles[header] = string(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) > 1 {
|
|
// Test Sender
|
|
path := os.Args[1]
|
|
host := os.Args[2]
|
|
file, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
log.Fatal("Check your Filepath. ", err)
|
|
}
|
|
Headers := map[string]string{
|
|
"User-Agent": "SendGrid-Test",
|
|
"Content-Type": "multipart/form-data; boundary=xYzZY",
|
|
}
|
|
method := rest.Post
|
|
request := rest.Request{
|
|
Method: method,
|
|
BaseURL: host,
|
|
Headers: Headers,
|
|
Body: file,
|
|
}
|
|
_, err = rest.API(request)
|
|
if err != nil {
|
|
log.Fatal("Check your Filepath. ", err)
|
|
}
|
|
} else {
|
|
conf := loadConfig("./conf.json")
|
|
http.HandleFunc("/", indexHandler)
|
|
http.HandleFunc(conf.Endpoint, inboundHandler)
|
|
port := os.Getenv("PORT")
|
|
if port == "" {
|
|
port = conf.Port
|
|
}
|
|
if err := http.ListenAndServe(port, nil); err != nil {
|
|
log.Fatalln("Error")
|
|
}
|
|
}
|
|
}
|