diff --git a/components/admin_tools.templ b/components/admin_tools.templ
index 583c721..e5a0a4e 100644
--- a/components/admin_tools.templ
+++ b/components/admin_tools.templ
@@ -36,6 +36,9 @@ type AdminToolsData struct {
LogFiles []LogFile
LogContent string
CurrentLogFile string
+ EmailTestSuccess *bool
+ EmailTestMessage string
+ SmtpServer string
}
// Dialog component for confirmation dialogs
@@ -463,6 +466,101 @@ templ AdminTools(ctx context.Context, data AdminToolsData) {
+
+
@BackupsList(data)
@@ -1000,3 +1098,74 @@ var Commit = "unknown"
func getCommit() string {
return Commit
}
+
+// EmailTestToast is a component for showing email test results
+templ EmailTestToast(success bool, message string) {
+
+
+
+ if success {
+
+ } else {
+
+ }
+
+
+
+ if success {
+ Email Sent Successfully
+ } else {
+ Email Sending Failed
+ }
+
+
+ { message }
+
+
+
+
+
+
+
+}
+
+// Add a style for the animate-fade-in animation
+script fadeInAnimation() {
+ // Add CSS animation if it doesn't exist
+ if (!document.getElementById('fade-in-animation')) {
+ const style = document.createElement('style');
+ style.id = 'fade-in-animation';
+ style.textContent = `
+ @keyframes fadeIn {
+ from { opacity: 0; transform: translateY(-10px); }
+ to { opacity: 1; transform: translateY(0); }
+ }
+ .animate-fade-in {
+ animation: fadeIn 0.3s ease-out forwards;
+ }
+ `;
+ document.head.appendChild(style);
+ }
+}
diff --git a/internal/email/email.go b/internal/email/email.go
index 7d7b9da..146c47b 100644
--- a/internal/email/email.go
+++ b/internal/email/email.go
@@ -270,3 +270,182 @@ func (s *Service) sendEmail(toEmail, subject, htmlContent string) error {
return client.Quit()
}
}
+
+// SendTestEmail sends a test email to verify email configuration
+func (s *Service) SendTestEmail(toEmail, subject, message string) error {
+ if !s.Config.Email.Enabled {
+ return fmt.Errorf("email service is disabled")
+ }
+
+ // Use default subject if not provided
+ if subject == "" {
+ subject = "Test Email from GoMFT"
+ }
+
+ // Use default message if not provided
+ if message == "" {
+ message = "This is a test email from GoMFT to verify the email configuration is working correctly."
+ }
+
+ // Create email data for template
+ data := map[string]interface{}{
+ "Subject": subject,
+ "Message": message,
+ "AppName": "GoMFT",
+ "Year": time.Now().Year(),
+ "SMTPServer": s.Config.Email.Host,
+ "SMTPPort": s.Config.Email.Port,
+ "FromEmail": s.Config.Email.FromEmail,
+ "CurrentTime": time.Now().Format(time.RFC1123Z),
+ }
+
+ // Generate email content
+ htmlContent, err := s.generateTestEmailHTML(data)
+ if err != nil {
+ return err
+ }
+
+ // Send the email
+ return s.sendEmail(toEmail, subject, htmlContent)
+}
+
+// generateTestEmailHTML generates the HTML content for test emails
+func (s *Service) generateTestEmailHTML(data map[string]interface{}) (string, error) {
+ // HTML template for test email
+ tmpl, err := template.New("testEmail").Parse(`
+
+
+
+
+
+
{{.Subject}}
+
+
+
+
+
+
+
{{.Message}}
+
+
+
+
SMTP Server:
+
{{.SMTPServer}}:{{.SMTPPort}}
+
+
+
From:
+
{{.FromEmail}}
+
+
+
Sent:
+
{{.CurrentTime}}
+
+
+
+
+
This is a test email sent from the GoMFT admin interface. If you've received this email, your email configuration is working correctly.
+
+
+
+
+
+
+`)
+ if err != nil {
+ return "", err
+ }
+
+ var result bytes.Buffer
+ if err := tmpl.Execute(&result, data); err != nil {
+ return "", err
+ }
+
+ return result.String(), nil
+}
diff --git a/internal/web/handlers/admin_tools_handlers.go b/internal/web/handlers/admin_tools_handlers.go
index 3ef70a9..2654afe 100644
--- a/internal/web/handlers/admin_tools_handlers.go
+++ b/internal/web/handlers/admin_tools_handlers.go
@@ -63,17 +63,28 @@ func (h *Handlers) HandleAdminTools(c *gin.Context) {
data.TotalUsers = int(totalUsers)
}
- // Get last backup time and backup count
- data.LastBackupTime, data.BackupCount = h.getBackupInfo()
+ // Get backup info (last backup time and count)
+ lastBackup, backupCount := h.getBackupInfo()
+ data.LastBackupTime = lastBackup
+ data.BackupCount = backupCount
// Get list of backup files
data.BackupFiles = h.getBackupFiles()
- // Check for maintenance issues
+ // Get maintenance message if any
data.MaintenanceMessage = h.checkMaintenanceIssues()
- // Render the admin tools page
- components.AdminTools(components.CreateTemplateContext(c), data).Render(c, c.Writer)
+ // Add SMTP server info if available
+ if h.Email != nil && h.Email.Config != nil && h.Email.Config.Email.Host != "" {
+ smtpServer := h.Email.Config.Email.Host
+ if h.Email.Config.Email.Port != 0 {
+ data.SmtpServer = fmt.Sprintf("%s:%d", smtpServer, h.Email.Config.Email.Port)
+ } else {
+ data.SmtpServer = smtpServer
+ }
+ }
+
+ components.AdminTools(c.Request.Context(), data).Render(c.Request.Context(), c.Writer)
}
// HandleBackupDatabase handles the backup database request
@@ -1368,3 +1379,43 @@ func (h *Handlers) HandleImportConfigsFromFile(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("%d configs imported successfully", imported)})
}
+
+// HandleTestEmail handles the POST /admin/test-email route
+func (h *Handlers) HandleTestEmail(c *gin.Context) {
+ // Parse the form
+ recipient := c.PostForm("recipient")
+ subject := c.PostForm("subject")
+ message := c.PostForm("message")
+
+ // Validate required fields
+ if recipient == "" {
+ components.EmailTestToast(false, "Recipient email is required").Render(c.Request.Context(), c.Writer)
+ return
+ }
+
+ // Get SMTP server info for display
+ smtpServer := ""
+ if h.Email != nil && h.Email.Config != nil && h.Email.Config.Email.Host != "" {
+ smtpServer = h.Email.Config.Email.Host
+ if h.Email.Config.Email.Port != 0 {
+ smtpServer = fmt.Sprintf("%s:%d", smtpServer, h.Email.Config.Email.Port)
+ }
+ }
+
+ // Send the test email
+ if h.Email == nil {
+ components.EmailTestToast(false, "Email service is not configured").Render(c.Request.Context(), c.Writer)
+ return
+ }
+
+ err := h.Email.SendTestEmail(recipient, subject, message)
+ if err != nil {
+ // Failed to send email
+ components.EmailTestToast(false, fmt.Sprintf("Failed to send email: %v", err)).Render(c.Request.Context(), c.Writer)
+ return
+ }
+
+ // Email sent successfully
+ successMsg := fmt.Sprintf("Test email sent successfully to %s", recipient)
+ components.EmailTestToast(true, successMsg).Render(c.Request.Context(), c.Writer)
+}
diff --git a/internal/web/handlers/routes.go b/internal/web/handlers/routes.go
index a84cac9..448627e 100644
--- a/internal/web/handlers/routes.go
+++ b/internal/web/handlers/routes.go
@@ -110,6 +110,9 @@ func (h *Handlers) RegisterRoutes(router *gin.Engine) {
admin.GET("/logs/refresh", h.HandleRefreshLogs)
admin.GET("/logs/view/:fileName", h.HandleViewLog)
admin.GET("/logs/download/:fileName", h.HandleDownloadLog)
+
+ // Email test route
+ admin.POST("/test-email", h.HandleTestEmail)
}
// API routes