diff --git a/app/cloud.go b/app/cloud.go index f045c57311..dba4422482 100644 --- a/app/cloud.go +++ b/app/cloud.go @@ -4,7 +4,9 @@ package app import ( + "bytes" "fmt" + "io" "net/http" "time" @@ -194,13 +196,25 @@ func (a *App) SendUpgradeConfirmationEmail(isYearly bool) *model.AppError { // we want to at least have one email sent out to an admin countNotOks := 0 + embeddedFiles := make(map[string]io.Reader) + if isYearly { + pdf, filename, pdfErr := a.Cloud().GetInvoicePDF("", subscription.LastInvoice.ID) + if pdfErr != nil { + a.Log().Error("Error retrieving the invoice for subscription id", mlog.String("subscription", subscription.ID), mlog.Err(pdfErr)) + } else { + embeddedFiles = map[string]io.Reader{ + filename: bytes.NewReader(pdf), + } + } + } + for _, admin := range sysAdmins { name := admin.FirstName if name == "" { name = admin.Username } - err := a.Srv().EmailService.SendCloudUpgradeConfirmationEmail(admin.Email, name, billingDate, admin.Locale, *a.Config().ServiceSettings.SiteURL, subscription.GetWorkSpaceNameFromDNS(), isYearly) + err := a.Srv().EmailService.SendCloudUpgradeConfirmationEmail(admin.Email, name, billingDate, admin.Locale, *a.Config().ServiceSettings.SiteURL, subscription.GetWorkSpaceNameFromDNS(), isYearly, embeddedFiles) if err != nil { a.Log().Error("Error sending trial ended email to", mlog.String("email", admin.Email), mlog.Err(err)) countNotOks++ diff --git a/app/email/email.go b/app/email/email.go index b24da7806c..fcf7651350 100644 --- a/app/email/email.go +++ b/app/email/email.go @@ -233,7 +233,7 @@ func (es *Service) SendWelcomeEmail(userID string, email string, verified bool, return nil } -func (es *Service) SendCloudUpgradeConfirmationEmail(userEmail, name, date, locale, siteURL, workspaceName string, isYearly bool) error { +func (es *Service) SendCloudUpgradeConfirmationEmail(userEmail, name, date, locale, siteURL, workspaceName string, isYearly bool, embeddedFiles map[string]io.Reader) error { T := i18n.GetUserTranslations(locale) subject := T("api.templates.cloud_upgrade_confirmation.subject") @@ -258,8 +258,14 @@ func (es *Service) SendCloudUpgradeConfirmationEmail(userEmail, name, date, loca return err } - if err := es.sendEmailWithCustomReplyTo(userEmail, subject, body, *es.config().SupportSettings.SupportEmail); err != nil { - return err + if isYearly { + if err := es.SendMailWithEmbeddedFilesAndCustomReplyTo(userEmail, subject, body, *es.config().SupportSettings.SupportEmail, embeddedFiles); err != nil { + return err + } + } else { + if err := es.sendEmailWithCustomReplyTo(userEmail, subject, body, *es.config().SupportSettings.SupportEmail); err != nil { + return err + } } return nil @@ -848,6 +854,13 @@ func (es *Service) sendMailWithCC(to, subject, htmlBody string, ccMail string) e return mail.SendMailUsingConfig(to, subject, htmlBody, mailConfig, license != nil && *license.Features.Compliance, "", "", "", ccMail) } +func (es *Service) SendMailWithEmbeddedFilesAndCustomReplyTo(to, subject, htmlBody, replyToAddress string, embeddedFiles map[string]io.Reader) error { + license := es.license() + mailConfig := es.mailServiceConfig(replyToAddress) + + return mail.SendMailWithEmbeddedFilesUsingConfig(to, subject, htmlBody, embeddedFiles, mailConfig, license != nil && *license.Features.Compliance, "", "", "", "") +} + func (es *Service) SendMailWithEmbeddedFiles(to, subject, htmlBody string, embeddedFiles map[string]io.Reader, messageID string, inReplyTo string, references string) error { license := es.license() mailConfig := es.mailServiceConfig("") diff --git a/app/email/email_test.go b/app/email/email_test.go index 2ad00123c3..76dd5524cd 100644 --- a/app/email/email_test.go +++ b/app/email/email_test.go @@ -4,6 +4,8 @@ package email import ( + "bytes" + "io" "os" "strings" "testing" @@ -280,11 +282,12 @@ func TestSendCloudUpgradedEmail(t *testing.T) { require.Contains(t, resultsEmail.Body.Text, "SomeName workspace has now been upgraded", "Wrong received message %s", resultsEmail.Body.Text) require.Contains(t, resultsEmail.Body.Text, "You'll be billed from", "Wrong received message %s", resultsEmail.Body.Text) require.Contains(t, resultsEmail.Body.Text, "Open Mattermost", "Wrong received message %s", resultsEmail.Body.Text) + require.Len(t, resultsEmail.Attachments, 0) } mail.DeleteMailBox(emailTo) // Send Update to Monthly Plan email - err := th.service.SendCloudUpgradeConfirmationEmail(emailTo, emailToUsername, "June 23, 2200", th.BasicUser.Locale, "https://example.com", "SomeName", false) + err := th.service.SendCloudUpgradeConfirmationEmail(emailTo, emailToUsername, "June 23, 2200", th.BasicUser.Locale, "https://example.com", "SomeName", false, make(map[string]io.Reader)) require.NoError(t, err) verifyMailbox(t) @@ -311,11 +314,15 @@ func TestSendCloudUpgradedEmail(t *testing.T) { require.Contains(t, resultsEmail.Body.Text, "You are now upgraded!", "Wrong received message %s", resultsEmail.Body.Text) require.Contains(t, resultsEmail.Body.Text, "SomeName workspace has now been upgraded", "Wrong received message %s", resultsEmail.Body.Text) require.Contains(t, resultsEmail.Body.Text, "View your invoice", "Wrong received message %s", resultsEmail.Body.Text) + require.Len(t, resultsEmail.Attachments, 1) } mail.DeleteMailBox(emailTo) // Send Update to Monthly Plan email - err := th.service.SendCloudUpgradeConfirmationEmail(emailTo, emailToUsername, "June 23, 2200", th.BasicUser.Locale, "https://example.com", "SomeName", true) + var embeddedFiles = map[string]io.Reader{ + "filename": bytes.NewReader([]byte("Test")), + } + err := th.service.SendCloudUpgradeConfirmationEmail(emailTo, emailToUsername, "June 23, 2200", th.BasicUser.Locale, "https://example.com", "SomeName", true, embeddedFiles) require.NoError(t, err) verifyMailbox(t) diff --git a/app/email/mocks/ServiceInterface.go b/app/email/mocks/ServiceInterface.go index 98b39f90fe..c42ce17982 100644 --- a/app/email/mocks/ServiceInterface.go +++ b/app/email/mocks/ServiceInterface.go @@ -125,13 +125,13 @@ func (_m *ServiceInterface) SendChangeUsernameEmail(newUsername string, _a1 stri return r0 } -// SendCloudUpgradeConfirmationEmail provides a mock function with given fields: userEmail, name, trialEndDate, locale, siteURL, workspaceName, isYearly -func (_m *ServiceInterface) SendCloudUpgradeConfirmationEmail(userEmail string, name string, trialEndDate string, locale string, siteURL string, workspaceName string, isYearly bool) error { - ret := _m.Called(userEmail, name, trialEndDate, locale, siteURL, workspaceName, isYearly) +// SendCloudUpgradeConfirmationEmail provides a mock function with given fields: userEmail, name, trialEndDate, locale, siteURL, workspaceName, isYearly, embeddedFiles +func (_m *ServiceInterface) SendCloudUpgradeConfirmationEmail(userEmail string, name string, trialEndDate string, locale string, siteURL string, workspaceName string, isYearly bool, embeddedFiles map[string]io.Reader) error { + ret := _m.Called(userEmail, name, trialEndDate, locale, siteURL, workspaceName, isYearly, embeddedFiles) var r0 error - if rf, ok := ret.Get(0).(func(string, string, string, string, string, string, bool) error); ok { - r0 = rf(userEmail, name, trialEndDate, locale, siteURL, workspaceName, isYearly) + if rf, ok := ret.Get(0).(func(string, string, string, string, string, string, bool, map[string]io.Reader) error); ok { + r0 = rf(userEmail, name, trialEndDate, locale, siteURL, workspaceName, isYearly, embeddedFiles) } else { r0 = ret.Error(0) } diff --git a/app/email/service.go b/app/email/service.go index d8745a1735..cb336c4fbf 100644 --- a/app/email/service.go +++ b/app/email/service.go @@ -129,7 +129,7 @@ type ServiceInterface interface { SendVerifyEmail(userEmail, locale, siteURL, token, redirect string) error SendSignInChangeEmail(email, method, locale, siteURL string) error SendWelcomeEmail(userID string, email string, verified bool, disableWelcomeEmail bool, locale, siteURL, redirect string) error - SendCloudUpgradeConfirmationEmail(userEmail, name, trialEndDate, locale, siteURL, workspaceName string, isYearly bool) error + SendCloudUpgradeConfirmationEmail(userEmail, name, trialEndDate, locale, siteURL, workspaceName string, isYearly bool, embeddedFiles map[string]io.Reader) error SendCloudWelcomeEmail(userEmail, locale, teamInviteID, workSpaceName, dns, siteURL string) error SendPasswordChangeEmail(email, method, locale, siteURL string) error SendUserAccessTokenAddedEmail(email, locale, siteURL string) error