From 14d5acf5e81c0b2f088b2016a9b9109f90ceb32a Mon Sep 17 00:00:00 2001 From: Rodrigue Chakode Date: Thu, 14 May 2020 14:58:22 +0200 Subject: [PATCH] improved sendmail + docs --- Makefile | 2 +- README.md | 83 +++++++++++++++++++++++++++++++----- app.yaml.sample | 6 +-- examples/demo-request.html | 28 ------------ main.go | 16 ++++--- model/hugo-contact-form.html | 37 ++++++++++++++++ sendmail.go | 33 +++++++------- 7 files changed, 139 insertions(+), 66 deletions(-) delete mode 100644 examples/demo-request.html create mode 100644 model/hugo-contact-form.html diff --git a/Makefile b/Makefile index 93b529d..97777a0 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ all: test build deploy: which gcloud gcloud components install app-engine-go - gcloud app deploy + gcloud app deploy --quiet build: $(GOBUILD) -o $(PACKAGE_NAME) -v diff --git a/README.md b/README.md index 9924fba..2746108 100644 --- a/README.md +++ b/README.md @@ -3,24 +3,85 @@ # Configuration variables +* Create the App Engine configuration file + ``` + cp app.yaml.sample app.yaml + ``` +* Edit the `app.yaml` file with your favorite editor and set the following environement variables appropriately: + ``` -SERVER_ADDR=":8393" -SMTP_SERVER_ADDR="mail.example.com:465" -SMTP_CLIENT_USERNAME="demo@example.com" -SMTP_CLIENT_PASSWORD="dem0ToBeChanged" -CONTACT_REPLY_EMAIL="noreply@example.com" -CONTACT_REPLY_CC_EMAIL="contact@example.com" -DEMO_URL="https://demo.example.com/" -ALLOWED_ORIGIN_DOMAIN="localhost:1313" -TEMPLATE_DEMO_REQUEST_REPLY=templates/template_demo_request_reply.html -TEMPLATE_CONTACT_REQUEST_REPLY=templates/template_contact_request_reply.html + SMTP_SERVER_ADDR: "smtp.mailgun.org:587" + SMTP_VERITY_CERT: true + SMTP_CLIENT_USERNAME: "postmaster@example.com" + SMTP_CLIENT_PASSWORD: "postmasterSecretPassWord" + CONTACT_REPLY_EMAIL: "noreply@example.com" + CONTACT_REPLY_CC_EMAIL: "contact@example.com" + DEMO_URL: "https://demo.example.com/" + ALLOWED_ORIGIN_DOMAIN: "example.com" ``` + +## Required HTTP Headers + +* `Origin` +* `Referer` + ## SMTP https://cloud.google.com/compute/docs/tutorials/sending-mail/using-mailgun?hl=fr +## Test +``` +curl -H'Origin: http://realopinsight.com' \ + -H'Referer: realopinsight.com' \ + -H'Content-Type: application/x-www-form-urlencoded' \ + -d 'target=contact' \ + -XPOST https://hugo-mx-gateway.ew.r.appspot.com/sendmail +``` # Build - ```sh make build ``` + +# Hugo Contact Form +See `./model/hugo-contact-form.html`. + + +``` +
+
+
+ Please fill in the form to submit your request +
+
+ + +
+
+ + +
+
+ + +
+ {{ if in .Params.tags "contact" }} +
+ + + +
+
+ + +
+ {{ else }} +
+ + +
+ {{ end }} + +
+
+
+``` diff --git a/app.yaml.sample b/app.yaml.sample index 05b03c8..1188fd8 100644 --- a/app.yaml.sample +++ b/app.yaml.sample @@ -5,9 +5,7 @@ env_variables: SMTP_VERITY_CERT: true SMTP_CLIENT_USERNAME: "postmaster@example.com" SMTP_CLIENT_PASSWORD: "postmasterSecretPassWord" + ALLOWED_ORIGINS: "127.0.0.1,example.com" CONTACT_REPLY_EMAIL: "noreply@example.com" CONTACT_REPLY_CC_EMAIL: "contact@example.com" - DEMO_URL: "https://demo.example.com/" - ALLOWED_ORIGIN_DOMAIN: "example.com" - TEMPLATE_DEMO_REQUEST_REPLY: templates/template_reply_demo_request.html - TEMPLATE_CONTACT_REQUEST_REPLY: templates/template_reply_contact_request.html \ No newline at end of file + DEMO_URL: "https://demo.example.com/" \ No newline at end of file diff --git a/examples/demo-request.html b/examples/demo-request.html deleted file mode 100644 index eefaa98..0000000 --- a/examples/demo-request.html +++ /dev/null @@ -1,28 +0,0 @@ -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- - -
\ No newline at end of file diff --git a/main.go b/main.go index b9f51c8..21d1697 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,8 @@ package main import ( "net/http" - "time" + "time" + "os" "github.com/spf13/viper" "github.com/gorilla/mux" @@ -76,7 +77,6 @@ func NewRouter() *mux.Router { func main() { viper.AutomaticEnv() - viper.SetDefault("SERVER_ADDR", ":8080") viper.SetDefault("SERVER_TLS_CERT", "/etc/cert/cert.pem") viper.SetDefault("SERVER_TLS_PRIVATEKEY", "/etc/cert/privkey.pem") viper.SetDefault("SMTP_SERVER_ADDR", "127.0.0.1:465") @@ -87,13 +87,17 @@ func main() { viper.SetDefault("EMAIL_SUBJECT", "Thanks to try our product") viper.SetDefault("DEMO_URL", "http://company.com/product-demo") + port := os.Getenv("PORT") + if port == "" { + port = "8080" + log.Infof("Defaulting to port %s", port) + } + router := NewRouter() - serverAddr := viper.GetString("SERVER_ADDR") + log.Infof("Listening on port %s", port) - log.Infof("Listening on %s", serverAddr) - - log.Fatal(http.ListenAndServe(serverAddr, router)) + log.Fatal(http.ListenAndServe(":"+port, router)) } diff --git a/model/hugo-contact-form.html b/model/hugo-contact-form.html new file mode 100644 index 0000000..81f87e8 --- /dev/null +++ b/model/hugo-contact-form.html @@ -0,0 +1,37 @@ +
+
+
+ Please fill in the form to submit your request +
+
+ + +
+
+ + +
+
+ + +
+ {{ if in .Params.tags "contact" }} +
+ + + +
+
+ + +
+ {{ else }} +
+ + +
+ {{ end }} + +
+
+
\ No newline at end of file diff --git a/sendmail.go b/sendmail.go index d6de036..6a5dda6 100644 --- a/sendmail.go +++ b/sendmail.go @@ -22,12 +22,12 @@ import ( "encoding/json" "fmt" "html/template" - "log" "net" "net/http" "net/smtp" "strings" + log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) @@ -79,7 +79,7 @@ func (m *SendMailRequest) Execute() error { // TLS config tlsconfig := &tls.Config{ - InsecureSkipVerify: true, + InsecureSkipVerify: viper.GetBool("SMTP_VERITY_CERT"), ServerName: smtpServerHost, } @@ -151,24 +151,25 @@ func (m *SendMailRequest) ParseTemplate(templateFileName string, data interface{ // SendMail handles HTTP request to send email func SendMail(httpResp http.ResponseWriter, httpReq *http.Request) { - AllowedOriginDomain := viper.GetString("ALLOWED_ORIGIN_DOMAIN") - AllowedOrigins := map[string]bool{ - fmt.Sprintf("http://%s", AllowedOriginDomain): true, - fmt.Sprintf("https://%s", AllowedOriginDomain): true, - fmt.Sprintf("http://www.%s", AllowedOriginDomain): true, - fmt.Sprintf("https://www.%s", AllowedOriginDomain): true, + allowedDomains := strings.Split(viper.GetString("ALLOWED_ORIGINS"), ",") + allowedOrigins := make(map[string]bool) + for _, domain := range allowedDomains { + domainTrimmed := strings.TrimSpace(domain) + allowedOrigins[fmt.Sprintf("http://%s", domainTrimmed)] = true + allowedOrigins[fmt.Sprintf("https://%s", domainTrimmed)] = true + allowedOrigins[fmt.Sprintf("http://www.%s", domainTrimmed)] = true + allowedOrigins[fmt.Sprintf("https://www.%s", domainTrimmed)] = true } - if len(httpReq.Header["Origin"]) == 0 || len(httpReq.Header["Referer"]) == 0 { rawHeader, _ := json.Marshal(httpReq.Header) - log.Println("request with unexpected headers:", string(rawHeader)) + log.Infoln("request with unexpected headers", string(rawHeader)) httpResp.WriteHeader(http.StatusForbidden) return } reqOrigin := httpReq.Header["Origin"][0] - if _, domainFound := AllowedOrigins[reqOrigin]; !domainFound { - log.Println("Not allowed origin:", reqOrigin) + if _, domainFound := allowedOrigins[reqOrigin]; !domainFound { + log.Errorln("not allowed origin", reqOrigin) httpResp.WriteHeader(http.StatusForbidden) return } @@ -191,13 +192,13 @@ func SendMail(httpResp http.ResponseWriter, httpReq *http.Request) { case "contact": recipients = []string{viper.GetString("CONTACT_REPLY_CC_EMAIL")} default: - log.Println("Not allowed request type:", contactRequest.RequestTarget) + log.Infoln("not allowed request type:", contactRequest.RequestTarget) httpResp.WriteHeader(http.StatusForbidden) return } userData, _ := json.Marshal(contactRequest) - log.Println("New Request:", string(userData)) + log.Infoln("New Request:", string(userData)) templateData := struct { Name string @@ -233,7 +234,7 @@ func SendMail(httpResp http.ResponseWriter, httpReq *http.Request) { if err == nil { err := sendMailReq.Execute() if err != nil { - log.Printf("error: %s", err.Error()) + log.Infof("error: %s", err.Error()) contactResponse.Status = "error" contactResponse.Message = fmt.Sprintf("An internal error occurred, please try later or send us an email at %s.", viper.GetString("CONTACT_REPLY_CC_EMAIL")) } else { @@ -245,7 +246,7 @@ func SendMail(httpResp http.ResponseWriter, httpReq *http.Request) { } } } else { - log.Printf("error: %s", err.Error()) + log.Infof("error: %s", err.Error()) contactResponse.Status = "error" contactResponse.Message = "Invalid request, please review your input and try again." }