From 2f9ff51c60b720fb71b7c650ab1fb76858af3baf Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 3 Apr 2026 19:57:51 +0200 Subject: [PATCH] feat(mail): add GetMailDomain helper for RFC 5322 compliant email IDs --- pkg/mail/domain.go | 36 ++++++++++++++++++++++++++++++++ pkg/mail/domain_test.go | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 pkg/mail/domain.go create mode 100644 pkg/mail/domain_test.go diff --git a/pkg/mail/domain.go b/pkg/mail/domain.go new file mode 100644 index 000000000..f3c65bec8 --- /dev/null +++ b/pkg/mail/domain.go @@ -0,0 +1,36 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mail + +import ( + "net/url" + + "code.vikunja.io/api/pkg/config" +) + +// GetMailDomain returns the hostname from the configured public URL, +// or "vikunja" as a fallback. Used for RFC 5322 compliant Message-ID +// and thread ID generation. +func GetMailDomain() string { + publicURL := config.ServicePublicURL.GetString() + if publicURL != "" { + if parsedURL, err := url.Parse(publicURL); err == nil && parsedURL.Hostname() != "" { + return parsedURL.Hostname() + } + } + return "vikunja" +} diff --git a/pkg/mail/domain_test.go b/pkg/mail/domain_test.go new file mode 100644 index 000000000..9055090d2 --- /dev/null +++ b/pkg/mail/domain_test.go @@ -0,0 +1,46 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mail + +import ( + "testing" + + "code.vikunja.io/api/pkg/config" + "github.com/stretchr/testify/assert" +) + +func TestGetMailDomain(t *testing.T) { + t.Run("returns fallback when public URL is empty", func(t *testing.T) { + config.ServicePublicURL.Set("") + assert.Equal(t, "vikunja", GetMailDomain()) + }) + + t.Run("extracts hostname from public URL", func(t *testing.T) { + config.ServicePublicURL.Set("https://tasks.example.com/") + assert.Equal(t, "tasks.example.com", GetMailDomain()) + }) + + t.Run("extracts hostname without port", func(t *testing.T) { + config.ServicePublicURL.Set("https://tasks.example.com:8080/") + assert.Equal(t, "tasks.example.com", GetMailDomain()) + }) + + t.Run("returns fallback for invalid URL", func(t *testing.T) { + config.ServicePublicURL.Set("://bad") + assert.Equal(t, "vikunja", GetMailDomain()) + }) +}