Compare commits

...

3 Commits
main ... emails

Author SHA1 Message Date
grandwizard28
d231aa1a7f feat: revamp invite email 2026-02-13 19:03:19 +05:30
grandwizard28
b251aa60bf feat: revamp invite email 2026-02-13 18:07:37 +05:30
grandwizard28
b166b20069 feat: revamp invite email 2026-02-13 18:06:40 +05:30
8 changed files with 139 additions and 21 deletions

View File

@@ -14,5 +14,8 @@
},
"[sql]": {
"editor.defaultFormatter": "adpyke.vscode-sql-formatter"
},
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
}
}

View File

@@ -193,6 +193,15 @@ emailing:
templates:
# The directory containing the email templates. This directory should contain a list of files defined at pkg/types/emailtypes/template.go.
directory: /opt/signoz/conf/templates/email
format:
header:
enabled: false
logo_url: ""
help:
enabled: false
email: ""
footer:
enabled: false
smtp:
# The SMTP server address.
address: localhost:25

View File

@@ -10,6 +10,27 @@ type Config struct {
type Templates struct {
Directory string `mapstructure:"directory"`
Format Format `mapstructure:"format"`
}
type Format struct {
Header Header `mapstructure:"header"`
Help Help `mapstructure:"help"`
Footer Footer `mapstructure:"footer"`
}
type Header struct {
Enabled bool `mapstructure:"enabled"`
LogoURL string `mapstructure:"logo_url"`
}
type Help struct {
Enabled bool `mapstructure:"enabled"`
Email string `mapstructure:"email"`
}
type Footer struct {
Enabled bool `mapstructure:"enabled"`
}
type SMTP struct {
@@ -45,6 +66,19 @@ func newConfig() factory.Config {
Enabled: false,
Templates: Templates{
Directory: "/root/templates",
Format: Format{
Header: Header{
Enabled: false,
LogoURL: "",
},
Help: Help{
Enabled: false,
Email: "",
},
Footer: Footer{
Enabled: false,
},
},
},
SMTP: SMTP{
Address: "localhost:25",

View File

@@ -15,6 +15,7 @@ type provider struct {
settings factory.ScopedProviderSettings
store emailtypes.TemplateStore
client *client.Client
config emailing.Config
}
func NewFactory() factory.ProviderFactory[emailing.Emailing, emailing.Config] {
@@ -55,7 +56,7 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
return nil, err
}
return &provider{settings: settings, store: store, client: client}, nil
return &provider{settings: settings, store: store, client: client, config: config}, nil
}
func (provider *provider) SendHTML(ctx context.Context, to string, subject string, templateName emailtypes.TemplateName, data map[string]any) error {
@@ -69,6 +70,9 @@ func (provider *provider) SendHTML(ctx context.Context, to string, subject strin
return err
}
data["format"] = provider.config.Templates.Format
data["to"] = to
content, err := emailtypes.NewContent(template, data)
if err != nil {
return err

View File

@@ -146,11 +146,9 @@ func (m *Module) CreateBulkInvite(ctx context.Context, orgID valuer.UUID, userID
continue
}
if err := m.emailing.SendHTML(ctx, invites[i].Email.String(), "You are invited to join a team in SigNoz", emailtypes.TemplateNameInvitationEmail, map[string]any{
"CustomerName": invites[i].Name,
"InviterName": creator.DisplayName,
"InviterEmail": creator.Email,
"Link": fmt.Sprintf("%s/signup?token=%s", bulkInvites.Invites[i].FrontendBaseUrl, invites[i].Token),
if err := m.emailing.SendHTML(ctx, invites[i].Email.String(), "You're Invited to Join SigNoz", emailtypes.TemplateNameInvitationEmail, map[string]any{
"inviter_email": creator.Email,
"link": fmt.Sprintf("%s/signup?token=%s", bulkInvites.Invites[i].FrontendBaseUrl, invites[i].Token),
}); err != nil {
m.settings.Logger().ErrorContext(ctx, "failed to send email", "error", err)
}

View File

@@ -16,7 +16,7 @@ var (
)
var (
TemplateNameInvitationEmail = TemplateName{valuer.NewString("invitation_email")}
TemplateNameInvitationEmail = TemplateName{valuer.NewString("invite")}
TemplateNameUpdateRole = TemplateName{valuer.NewString("update_role")}
TemplateNameResetPassword = TemplateName{valuer.NewString("reset_password_email")}
)

View File

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<p>Hi {{.CustomerName}},</p>
<p>You have been invited to join SigNoz project by {{.InviterName}} ({{.InviterEmail}}).</p>
<p>Please click on the following button to accept the invitation:</p>
<a href="{{.Link}}" style="background-color: #000000; color: white; padding: 14px 20px; text-align: center; text-decoration: none; display: inline-block;">Accept Invitation</a>
<p>Button not working? Paste the following link into your browser:</p>
<p>{{.Link}}</p>
<p>Follow docs here 👉 to <a href="https://signoz.io/docs/cloud/">Get Started with SigNoz Cloud</a></p>
<p>Thanks,</p>
<p>SigNoz Team</p>
</body>
</html>

View File

@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>You're Invited to Join SigNoz</title>
</head>
<body
style="margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;line-height:1.6;color:#333;background:#fff">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="background:#fff">
<tr>
<td align="center" style="padding:0">
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0"
style="max-width:600px;width:100%">
{{ if .format.Header.Enabled }}
<tr>
<td align="center" style="padding:40px 20px 24px">
<img src="{{.format.Header.LogoURL}}" alt="SigNoz" width="160" height="40"
style="display:block;border:0;outline:none;max-width:100%;height:auto">
</td>
</tr>
{{ end }}
<tr>
<td style="padding:24px 20px 32px">
<p style="margin:0 0 24px;font-size:16px;color:#1a1a1a">Hi there,</p>
<p style="margin:0 0 24px;font-size:16px;color:#333;line-height:1.6">You've been invited by
<strong>{{.inviter_email}}</strong> to join their SigNoz organization.
</p>
<p style="margin:0 0 16px;font-size:16px;color:#333;line-height:1.6">A new account has been created for
you with the following details:</p>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"
style="margin:0 0 24px">
<tr>
<td style="padding:20px;background:#f5f5f5;border-radius:6px;border-left:4px solid #4E74F8">
<p style="margin:0;font-size:15px;color:#333;line-height:1.6"><strong>Email:</strong> {{.to}}</p>
</td>
</tr>
</table>
<p style="margin:0 0 24px;font-size:16px;color:#333;line-height:1.6">Accept the invitation to get started.
</p>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"
style="margin:0 0 16px">
<tr>
<td align="center">
<a href="{{.link}}" target="_blank"
style="display:inline-block;padding:16px 48px;font-size:16px;font-weight:600;color:#fff;background:#4E74F8;text-decoration:none;border-radius:4px">Accept
Invitation</a>
</td>
</tr>
</table>
<p style="margin:0 0 4px;font-size:13px;color:#666;text-align:center">Button not working? Copy and paste
this link into your browser:</p>
<p style="margin:0 0 32px;font-size:13px;color:#4E74F8;word-break:break-all;text-align:center"><a
href="{{.link}}" style="color:#4E74F8;text-decoration:none">{{.link}}</a></p>
{{ if .format.Help.Enabled }}
<p style="margin:0 0 32px;font-size:16px;color:#333;line-height:1.6">Need help? Chat with our team in the
SigNoz application or email us at <a href="mailto:{{.format.Help.Email}}"
style="color:#4E74F8;text-decoration:none">{{.format.Help.Email}}</a>.</p>
{{ end }}
<p style="margin:0;font-size:16px;color:#333;line-height:1.6">Thanks,<br><strong>The SigNoz Team</strong>
</p>
</td>
</tr>
{{ if .format.Footer.Enabled }}
<tr>
<td align="center" style="padding:32px 20px 40px">
<p style="margin:0 0 8px;font-size:12px;color:#999;line-height:1.5"><a
href="https://signoz.io/terms-of-service/" style="color:#4E74F8;text-decoration:none">Terms of
Service</a> - <a href="https://signoz.io/privacy/" style="color:#4E74F8;text-decoration:none">Privacy
Policy</a></p>
<p style="margin:0;font-size:12px;color:#999;line-height:1.5">©2026 SigNoz Inc.</p>
</td>
</tr>
{{ end }}
</table>
</td>
</tr>
</table>
</body>
</html>