From ee448170ef9ae8f315f6e55316b3f36e33fe2561 Mon Sep 17 00:00:00 2001 From: Kailash Nadh Date: Mon, 11 Jul 2022 18:54:38 +0530 Subject: [PATCH] Add support for testing SMTP connections in the settings UI. --- cmd/handlers.go | 1 + cmd/settings.go | 66 ++++++++++++ frontend/src/api/index.js | 3 + frontend/src/utils.js | 8 +- frontend/src/views/settings/smtp.vue | 121 ++++++++++++++++++---- go.mod | 2 +- go.sum | 2 + i18n/cs-cz.json | 3 + i18n/de.json | 3 + i18n/en.json | 2 + i18n/es.json | 3 + i18n/fi.json | 3 + i18n/fr.json | 3 + i18n/hu.json | 3 + i18n/it.json | 3 + i18n/jp.json | 3 + i18n/ml.json | 3 + i18n/nl.json | 3 + i18n/pl.json | 3 + i18n/pt-BR.json | 3 + i18n/pt.json | 3 + i18n/ro.json | 3 + i18n/ru.json | 3 + i18n/tr.json | 3 + i18n/vi.json | 3 + static/email-templates/import-status.html | 2 +- static/email-templates/smtp-test.html | 5 + 27 files changed, 237 insertions(+), 26 deletions(-) create mode 100644 static/email-templates/smtp-test.html diff --git a/cmd/handlers.go b/cmd/handlers.go index 3758401..d7aac6a 100644 --- a/cmd/handlers.go +++ b/cmd/handlers.go @@ -68,6 +68,7 @@ func initHTTPHandlers(e *echo.Echo, app *App) { g.GET("/api/settings", handleGetSettings) g.PUT("/api/settings", handleUpdateSettings) + g.POST("/api/settings/smtp/test", handleTestSMTPSettings) g.POST("/api/admin/reload", handleReloadApp) g.GET("/api/logs", handleGetLogs) diff --git a/cmd/settings.go b/cmd/settings.go index 55c98cb..5f86a29 100644 --- a/cmd/settings.go +++ b/cmd/settings.go @@ -1,6 +1,8 @@ package main import ( + "bytes" + "io/ioutil" "net/http" "regexp" "strings" @@ -8,6 +10,11 @@ import ( "time" "github.com/gofrs/uuid" + "github.com/knadh/koanf" + "github.com/knadh/koanf/parsers/json" + "github.com/knadh/koanf/providers/rawbytes" + "github.com/knadh/listmonk/internal/messenger" + "github.com/knadh/listmonk/internal/messenger/email" "github.com/knadh/listmonk/models" "github.com/labstack/echo/v4" ) @@ -193,3 +200,62 @@ func handleGetLogs(c echo.Context) error { app := c.Get("app").(*App) return c.JSON(http.StatusOK, okResp{app.bufLog.Lines()}) } + +// handleTestSMTPSettings returns the log entries stored in the log buffer. +func handleTestSMTPSettings(c echo.Context) error { + app := c.Get("app").(*App) + + // Copy the raw JSON post body. + reqBody, err := ioutil.ReadAll(c.Request().Body) + if err != nil { + app.log.Printf("error reading SMTP test: %v", err) + return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.internalError")) + } + + // Load the JSON into koanf to parse SMTP settings properly including timestrings. + ko := koanf.New(".") + if err := ko.Load(rawbytes.Provider(reqBody), json.Parser()); err != nil { + app.log.Printf("error unmarshalling SMTP test request: %v", err) + return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.internalError")) + } + + req := email.Server{} + if err := ko.UnmarshalWithConf("", &req, koanf.UnmarshalConf{Tag: "json"}); err != nil { + app.log.Printf("error scanning SMTP test request: %v", err) + return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.internalError")) + } + + to := ko.String("email") + if to == "" { + return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.missingFields", "name", "email")) + } + + // Initialize a new SMTP pool. + req.MaxConns = 1 + req.IdleTimeout = time.Second * 2 + req.PoolWaitTimeout = time.Second * 2 + msgr, err := email.New(req) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, + app.i18n.Ts("globals.messages.errorCreating", "name", "SMTP", "error", err.Error())) + } + + var b bytes.Buffer + if err := app.notifTpls.tpls.ExecuteTemplate(&b, "smtp-test", nil); err != nil { + app.log.Printf("error compiling notification template '%s': %v", "smtp-test", err) + return err + } + + m := messenger.Message{} + m.ContentType = app.notifTpls.contentType + m.From = app.constants.FromEmail + m.To = []string{to} + m.Subject = app.i18n.T("settings.smtp.testConnection") + m.Body = b.Bytes() + if err := msgr.Push(m); err != nil { + app.log.Printf("error sending SMTP test (%s): %v", m.Subject, err) + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + + return c.JSON(http.StatusOK, okResp{app.bufLog.Lines()}) +} diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 0fab357..99a2047 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -277,6 +277,9 @@ export const getSettings = async () => http.get('/api/settings', export const updateSettings = async (data) => http.put('/api/settings', data, { loading: models.settings }); +export const testSMTP = async (data) => http.post('/api/settings/smtp/test', data, + { loading: models.settings, disableToast: true }); + export const getLogs = async () => http.get('/api/logs', { loading: models.logs, camelCase: false }); diff --git a/frontend/src/utils.js b/frontend/src/utils.js index 5bb3b61..f7d97ff 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -141,12 +141,14 @@ export default class Utils { }); }; - prompt = (msg, inputAttrs, onConfirm, onCancel) => { + prompt = (msg, inputAttrs, onConfirm, onCancel, params) => { + const p = params || {}; + Dialog.prompt({ scroll: 'keep', message: this.escapeHTML(msg), - confirmText: this.i18n.t('globals.buttons.ok'), - cancelText: this.i18n.t('globals.buttons.cancel'), + confirmText: p.confirmText || this.i18n.t('globals.buttons.ok'), + cancelText: p.cancelText || this.i18n.t('globals.buttons.cancel'), inputAttrs: { type: 'string', maxlength: 200, diff --git a/frontend/src/views/settings/smtp.vue b/frontend/src/views/settings/smtp.vue index 39cca4f..7128ff1 100644 --- a/frontend/src/views/settings/smtp.vue +++ b/frontend/src/views/settings/smtp.vue @@ -134,29 +134,63 @@ + +
+ +

-
-

- - {{ $t('settings.smtp.setCustomHeaders') }} -

- - - -
+
+
+ +
+ + {{ $t('settings.smtp.sendTest') }} + + + {{ $t('settings.smtp.testConnection') }} + +
+
+
+
+
+
+
+ + + +
+
+ -
-
- - {{ $t('settings.smtp.testConnection') }} - -
-
@@ -168,6 +202,7 @@ diff --git a/go.mod b/go.mod index e91a8ee..3c37345 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/knadh/go-pop3 v0.3.0 github.com/knadh/goyesql/v2 v2.1.2 github.com/knadh/koanf v1.2.3 - github.com/knadh/smtppool v0.4.0 + github.com/knadh/smtppool v1.0.0 github.com/knadh/stuffbin v1.1.0 github.com/labstack/echo/v4 v4.6.1 github.com/labstack/gommon v0.3.1 // indirect diff --git a/go.sum b/go.sum index 494ae9a..6b5b3f4 100644 --- a/go.sum +++ b/go.sum @@ -84,6 +84,8 @@ github.com/knadh/koanf v1.2.3 h1:2Rkr0YhhYk+4QEOm800Q3Pu0Wi87svTxM6uuEb4WhYw= github.com/knadh/koanf v1.2.3/go.mod h1:xpPTwMhsA/aaQLAilyCCqfpEiY1gpa160AiCuWHJUjY= github.com/knadh/smtppool v0.4.0 h1:335iXPwZ6katJVhauV4O6e8uPvvPmO6YLrfDQhb6UvE= github.com/knadh/smtppool v0.4.0/go.mod h1:3DJHouXAgPDBz0kC50HukOsdapYSwIEfJGwuip46oCA= +github.com/knadh/smtppool v1.0.0 h1:1c8A7+nD8WdMMzvd3yY5aoY9QBgyGTA+Iq1IdlgKGJw= +github.com/knadh/smtppool v1.0.0/go.mod h1:3DJHouXAgPDBz0kC50HukOsdapYSwIEfJGwuip46oCA= github.com/knadh/stuffbin v1.1.0 h1:f5S5BHzZALjuJEgTIOMC9NidEnBJM7Ze6Lu1GHR/lwU= github.com/knadh/stuffbin v1.1.0/go.mod h1:yVCFaWaKPubSNibBsTAJ939q2ABHudJQxRWZWV5yh+4= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/i18n/cs-cz.json b/i18n/cs-cz.json index 14352e3..e23456c 100644 --- a/i18n/cs-cz.json +++ b/i18n/cs-cz.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Opakování", "settings.smtp.retriesHelp": "Počet opakovaných pokusů, když zpráva selže.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Nastavit vlastní záhlaví", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Nastavení", "settings.updateAvailable": "Nová aktualizace {version} je k dispozici.", "subscribers.advancedQuery": "Rozšířené", diff --git a/i18n/de.json b/i18n/de.json index cd13c5c..a301582 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Wiederholungen", "settings.smtp.retriesHelp": "Maximale Anzahl an Wiederholungen, wenn eine Machricht fehlschlägt.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Benutzerdefinierten Header verwenden", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Einstellungen", "settings.updateAvailable": "Ein neues Update auf {version} ist verfügbar.", "subscribers.advancedQuery": "Erweitert", diff --git a/i18n/en.json b/i18n/en.json index 52cebfc..89906c1 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -452,8 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Retries", "settings.smtp.retriesHelp": "Number of times to retry when a message fails.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Set custom headers", "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Settings", "settings.updateAvailable": "A new update {version} is available.", "subscribers.advancedQuery": "Advanced", diff --git a/i18n/es.json b/i18n/es.json index 0a7dbc1..f5b5751 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Reintentos", "settings.smtp.retriesHelp": "Número de reintentos cuando un mensaje falla.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Configurar encabezados personalizados.", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Configuraciones", "settings.updateAvailable": "Una actualización {version} está disponible.", "subscribers.advancedQuery": "Avanzado", diff --git a/i18n/fi.json b/i18n/fi.json index 4e1f6f9..7ef0c22 100644 --- a/i18n/fi.json +++ b/i18n/fi.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Retries", "settings.smtp.retriesHelp": "Number of times to retry when a message fails.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Set custom headers", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Settings", "settings.updateAvailable": "A new update {version} is available.", "subscribers.advancedQuery": "Advanced", diff --git a/i18n/fr.json b/i18n/fr.json index fde35ac..b72b22e 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Tentatives de renvoi", "settings.smtp.retriesHelp": "Nombre de tentatives de renvoi d'un message en cas d'échec", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Définir des en-têtes personnalisés", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Paramètres", "settings.updateAvailable": "Une nouvelle version ({version}) est disponible.", "subscribers.advancedQuery": "Requête avancée", diff --git a/i18n/hu.json b/i18n/hu.json index cc4fe4c..dcf66e6 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Újrapróbálkozások", "settings.smtp.retriesHelp": "Az újrapróbálkozások száma, ha az üzenet sikertelen.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Egyéni fejlécek beállítása", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Beállítások", "settings.updateAvailable": "Új frissítés {version} elérhető.", "subscribers.advancedQuery": "További beállítások", diff --git a/i18n/it.json b/i18n/it.json index 4f7a79e..071af2d 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Tentativi", "settings.smtp.retriesHelp": "Numero di tentativi in caso di errore invio messaggio.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Definisci intestazioni personalizzate", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Impostazioni", "settings.updateAvailable": "È a disposizione una nuova versione {version}.", "subscribers.advancedQuery": "Avanzate", diff --git a/i18n/jp.json b/i18n/jp.json index af95641..c4e957d 100644 --- a/i18n/jp.json +++ b/i18n/jp.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "再トライ", "settings.smtp.retriesHelp": "メッセージ送信失敗時の再試行数", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "カスタムヘッダー設定", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "設定", "settings.updateAvailable": "新しい {バージョン} の更新が可能です。", "subscribers.advancedQuery": "アドバンスド", diff --git a/i18n/ml.json b/i18n/ml.json index f669c38..0d26cab 100644 --- a/i18n/ml.json +++ b/i18n/ml.json @@ -452,7 +452,10 @@ "settings.smtp.name": "എസ്. എം. ടീ. പി", "settings.smtp.retries": "പുനഃശ്രമങ്ങൾ", "settings.smtp.retriesHelp": "സന്ദേശമയ്ക്കുന്നത് പരാജയപ്പെട്ടാൽ എത്ര തവണ വീണ്ടും ശ്രമിക്കണം.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "ഇഷ്‌ടാനുസൃത തലക്കെട്ടുകൾ നൽകുക", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "ക്രമീകരണങ്ങൾ", "settings.updateAvailable": "A new update {version} is available.", "subscribers.advancedQuery": "വിപുലമായത്", diff --git a/i18n/nl.json b/i18n/nl.json index c4128dd..1006ce6 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Nieuwe pogingen", "settings.smtp.retriesHelp": "Aantal keer om opnieuw te proberen als een bericht mislukt.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Stel custom headers in", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Instellingen", "settings.updateAvailable": "Een nieuwe update {version} is beschikbaar.", "subscribers.advancedQuery": "Geavanceerd", diff --git a/i18n/pl.json b/i18n/pl.json index 1d3c834..4f3f2b9 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Ponowne próby", "settings.smtp.retriesHelp": "Liczba ponownych prób przy niepowodzeniu", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Ustaw niestandardowe nagłówki", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Ustawienia", "settings.updateAvailable": "Nowa wersja {version} jest dostępna.", "subscribers.advancedQuery": "Zaawansowane", diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 9c93d06..3392cce 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Tentativas", "settings.smtp.retriesHelp": "Número de tentativas quando uma mensagem falhar.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Definir cabeçalhos personalizados", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Configurações", "settings.updateAvailable": "Atualização: a nova versão {version} já está disponível.", "subscribers.advancedQuery": "Avançado", diff --git a/i18n/pt.json b/i18n/pt.json index ea7dd52..39df546 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Tentativas", "settings.smtp.retriesHelp": "Número de vezes para tentar novamente quando uma mensagem falha.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Colocar headers customizados", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Definições", "settings.updateAvailable": "A new update {version} is available.", "subscribers.advancedQuery": "Avançado", diff --git a/i18n/ro.json b/i18n/ro.json index 41d371c..29e2e34 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Reîncercări", "settings.smtp.retriesHelp": "De câte ori trebuie să reîncercați când un mesaj eșuează.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Setează anteturi personalizate", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Setări", "settings.updateAvailable": "Este disponibilă o nouă actualizare {versiune}.", "subscribers.advancedQuery": "Avansat", diff --git a/i18n/ru.json b/i18n/ru.json index 3616f09..8574088 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Повторные попытки", "settings.smtp.retriesHelp": "Количество повторных попыток после ошибки отправки сообщения.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Установка настраиваемых заголовков", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Параметры", "settings.updateAvailable": "Доступна новая версия: {version}.", "subscribers.advancedQuery": "Дополнительно", diff --git a/i18n/tr.json b/i18n/tr.json index aa67101..2592802 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Tekrarlama", "settings.smtp.retriesHelp": "Mesaj hata verdiğinde tekrar deneme sayısı.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Özel başlık tanımla", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Ayarlar", "settings.updateAvailable": "Yeni bir güncel sürüm {version} mevcuttur.", "subscribers.advancedQuery": "İleri düzey", diff --git a/i18n/vi.json b/i18n/vi.json index fc20d74..fa60c65 100644 --- a/i18n/vi.json +++ b/i18n/vi.json @@ -452,7 +452,10 @@ "settings.smtp.name": "SMTP", "settings.smtp.retries": "Thử lại", "settings.smtp.retriesHelp": "Số lần thử lại khi có thông báo không thành công.", + "settings.smtp.sendTest": "Send e-mail", "settings.smtp.setCustomHeaders": "Đặt tiêu đề tùy chỉnh", + "settings.smtp.testConnection": "Test connection", + "settings.smtp.toEmail": "To e-mail", "settings.title": "Cài đặt", "settings.updateAvailable": "Đã có bản cập nhật mới {version}.", "subscribers.advancedQuery": "Trình độ cao", diff --git a/static/email-templates/import-status.html b/static/email-templates/import-status.html index 0531205..39748cc 100644 --- a/static/email-templates/import-status.html +++ b/static/email-templates/import-status.html @@ -16,4 +16,4 @@ {{ template "footer" }} -{{ end }} \ No newline at end of file +{{ end }} diff --git a/static/email-templates/smtp-test.html b/static/email-templates/smtp-test.html new file mode 100644 index 0000000..61cfb38 --- /dev/null +++ b/static/email-templates/smtp-test.html @@ -0,0 +1,5 @@ +{{ define "smtp-test" }} +{{ template "header" . }} +

{{ L.Ts "settings.smtp.testConnection" }}

+{{ template "footer" }} +{{ end }}