diff --git a/main.go b/main.go index 04946c6..2695134 100644 --- a/main.go +++ b/main.go @@ -2,13 +2,108 @@ package main import ( "encoding/json" + "fmt" + "html" "log" "net/http" "strings" + "strconv" "gopkg.in/gomail.v2" ) +// Copyable snippets used by /docs and dedicated snippet endpoints +const docsHTMLSnippet = ` +
+
+ +
+
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
` + +const docsJSSnippet = ` +// Contact form submission +const form = document.getElementById('contact-form'); +if (form) { + form.addEventListener('submit', async (e) => { + e.preventDefault(); + + const submitButton = form.querySelector('button[type="submit"]'); + const originalButtonText = submitButton.innerHTML; + + try { + // Show loading state + submitButton.disabled = true; + submitButton.innerHTML = 'Odesílám...'; + + const data = Object.fromEntries(new FormData(form)); + + const res = await fetch('https://sendmail.tdvorak.dev/send' + window.location.search, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }); + + const text = await res.text(); + + if (res.ok) { + // Show success message + alert('Děkujeme za vaši zprávu! Brzy se vám ozveme zpět.'); + form.reset(); + } else { + throw new Error(text || 'Něco se pokazilo. Zkuste to prosím znovu.'); + } + } catch (error) { + console.error('Error:', error); + alert(error.message || 'Při odesílání zprávy došlo k chybě. Zkuste to prosím znovu později.'); + } finally { + // Reset button state + submitButton.disabled = false; + submitButton.innerHTML = originalButtonText; + } + }); +}` + type FormData struct { Domain string `json:"domain"` Name string `json:"name"` @@ -17,6 +112,85 @@ type FormData struct { Message string `json:"message"` } +// rootHandler serves a minimal HTML page with a contact form and JS to submit to /send +func rootHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "GET only", http.StatusMethodNotAllowed) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + htmlEsc := html.EscapeString(docsHTMLSnippet) + jsEsc := html.EscapeString(docsJSSnippet) + page := fmt.Sprintf(` + + + + + SendMail API – Dokumentace + + + +
+

SendMail API

+

Server: http://localhost:8080

+ +
+

1) POST /send

+

Tělo JSON: { domain?, name, email, subject, message }

+

Volitelné SMTP v query: ?email=&pass=&server=&port=

+

Příklad cURL (přednastavená doména)

+
curl -X POST http://localhost:8080/send \
+  -H "Content-Type: application/json" \
+  -d '{
+    "domain":"sportcreative.eu",
+    "name":"Jan Novák",
+    "email":"jan@example.com",
+    "subject":"Dotaz",
+    "message":"Dobrý den..."
+  }'
+      
+

Příklad cURL (SMTP v URL)

+
curl -X POST "http://localhost:8080/send?email=USER@example.com&pass=SECRET&server=smtp.example.com&port=465" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "name":"Jan Novák",
+    "email":"jan@example.com",
+    "subject":"Dotaz",
+    "message":"Dobrý den..."
+  }'
+      
+
+ +
+

2) GET /send-params

+

Query: ?email=&pass=&server=&port=&to=&from=&subject=&message= (když chybí to/from, použije se email).

+

Příklad cURL

+
curl "http://localhost:8080/send-params?email=USER@example.com&pass=SECRET&server=smtp.example.com&port=465&to=dest@example.com&from=USER@example.com&subject=Hello&message=Ahoj"
+
+ +
+

HTML formulář (vložit do stránky)

+
%s
+
+ +
+

JavaScript (vložit do stránky)

+
%s
+
+
+ +`, htmlEsc, jsEsc) + w.Write([]byte(page)) +} + type EmailConfig struct { Email string Password string @@ -44,16 +218,41 @@ func sendHandler(w http.ResponseWriter, r *http.Request) { return } - data.Domain = strings.ToLower(strings.TrimSpace(data.Domain)) - config, ok := domainMap[data.Domain] - if !ok { - http.Error(w, "Unknown domain", http.StatusUnauthorized) - return + // Determine SMTP configuration: prefer query params if provided; otherwise use domain map + q := r.URL.Query() + qEmail := strings.TrimSpace(q.Get("email")) + qPass := q.Get("pass") + qServer := strings.TrimSpace(q.Get("server")) + qPortStr := strings.TrimSpace(q.Get("port")) + + var config EmailConfig + if qEmail != "" || qPass != "" || qServer != "" || qPortStr != "" { + if qEmail == "" || qPass == "" || qServer == "" || qPortStr == "" { + http.Error(w, "Missing required query params: email, pass, server, port", http.StatusBadRequest) + return + } + port, err := strconv.Atoi(qPortStr) + if err != nil || port <= 0 { + http.Error(w, "Invalid port", http.StatusBadRequest) + return + } + config = EmailConfig{Email: qEmail, Password: qPass, SMTPHost: qServer, SMTPPort: port} + } else { + data.Domain = strings.ToLower(strings.TrimSpace(data.Domain)) + var ok bool + config, ok = domainMap[data.Domain] + if !ok { + http.Error(w, "Unknown domain", http.StatusUnauthorized) + return + } } m := gomail.NewMessage() m.SetHeader("From", config.Email) m.SetHeader("To", config.Email) // you can change this to forward to another inbox + if strings.TrimSpace(data.Email) != "" { + m.SetHeader("Reply-To", data.Email) + } m.SetHeader("Subject", data.Subject) m.SetBody("text/plain", "Name: "+data.Name+"\nEmail: "+data.Email+"\n\n"+data.Message) @@ -89,8 +288,72 @@ func enableCors(handler http.HandlerFunc) http.HandlerFunc { } } -func main() { - http.HandleFunc("/send", enableCors(sendHandler)) - log.Println("Server running on :8080") - log.Fatal(http.ListenAndServe(":8080", nil)) +// sendParamsHandler handles sending email with explicit SMTP parameters via query string. +// Example: +// GET /send-params?email=user@example.com&pass=secret&server=smtp.example.com&port=465&to=dest@example.com&from=user@example.com&subject=Hello&message=Hi +func sendParamsHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "GET only", http.StatusMethodNotAllowed) + return + } + + q := r.URL.Query() + smtpEmail := strings.TrimSpace(q.Get("email")) + smtpPass := q.Get("pass") + smtpServer := strings.TrimSpace(q.Get("server")) + portStr := strings.TrimSpace(q.Get("port")) + to := strings.TrimSpace(q.Get("to")) + from := strings.TrimSpace(q.Get("from")) + subject := q.Get("subject") + message := q.Get("message") + + if smtpEmail == "" || smtpPass == "" || smtpServer == "" || portStr == "" { + http.Error(w, "Missing required params: email, pass, server, port", http.StatusBadRequest) + return + } + + port, err := strconv.Atoi(portStr) + if err != nil || port <= 0 { + http.Error(w, "Invalid port", http.StatusBadRequest) + return + } + + if from == "" { + from = smtpEmail + } + if to == "" { + to = smtpEmail + } + + m := gomail.NewMessage() + m.SetHeader("From", from) + m.SetHeader("To", to) + if subject == "" { + subject = "(no subject)" + } + m.SetHeader("Subject", subject) + m.SetBody("text/plain", message) + + d := gomail.NewDialer(smtpServer, port, smtpEmail, smtpPass) + d.SSL = true + + if err := d.DialAndSend(m); err != nil { + log.Println("Email send error:", err) + http.Error(w, "Failed to send email", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]string{"status": "ok", "message": "Email sent successfully"}) } + +// docsHandler serves a minimal JSON API description. + +func main() { + http.HandleFunc("/send", enableCors(sendHandler)) + http.HandleFunc("/send-params", enableCors(sendParamsHandler)) + http.HandleFunc("/", enableCors(rootHandler)) + log.Println("Server running on :8080") + log.Fatal(http.ListenAndServe(":8080", nil)) +} +