-
-
Notifications
You must be signed in to change notification settings - Fork 377
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: smtp server for sending email can now be set by config
- Loading branch information
1 parent
e25a426
commit 9f27bd1
Showing
7 changed files
with
131 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,8 +17,9 @@ user = 'taskcafe' | |
password = 'taskcafe_test' | ||
|
||
[smtp] | ||
username = '[email protected]' | ||
password = 'example' | ||
server = 'mail.example.com' | ||
port = 465 | ||
connection_security = 'STARTTLS' | ||
username = '[email protected]' | ||
password = '' | ||
from = '[email protected]' | ||
host = 'localhost' | ||
port = 11500 | ||
skip_verify = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import ( | |
|
||
"github.com/jmoiron/sqlx" | ||
"github.com/jordanknott/taskcafe/internal/route" | ||
"github.com/jordanknott/taskcafe/internal/utils" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
|
@@ -75,11 +76,25 @@ func newWebCmd() *cobra.Command { | |
log.Warn("server.secret is not set, generating a random secret") | ||
secret = uuid.New().String() | ||
} | ||
r, _ := route.NewRouter(db, []byte(secret)) | ||
r, _ := route.NewRouter(db, utils.EmailConfig{ | ||
From: viper.GetString("smtp.from"), | ||
Host: viper.GetString("smtp.host"), | ||
Port: viper.GetInt("smtp.port"), | ||
Username: viper.GetString("smtp.username"), | ||
Password: viper.GetString("smtp.password"), | ||
InsecureSkipVerify: viper.GetBool("smtp.skip_verify"), | ||
}, []byte(secret)) | ||
return http.ListenAndServe(viper.GetString("server.hostname"), r) | ||
}, | ||
} | ||
|
||
viper.SetDefault("smtp.from", "[email protected]") | ||
viper.SetDefault("smtp.host", "localhost") | ||
viper.SetDefault("smtp.port", 587) | ||
viper.SetDefault("smtp.username", "") | ||
viper.SetDefault("smtp.password", "") | ||
viper.SetDefault("smtp.skip_verify", false) | ||
|
||
cc.Flags().Bool("migrate", false, "if true, auto run's schema migrations before starting the web server") | ||
|
||
viper.BindPFlag("migrate", cc.Flags().Lookup("migrate")) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ package graph | |
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"database/sql" | ||
"encoding/json" | ||
"errors" | ||
|
@@ -16,12 +15,11 @@ import ( | |
"github.com/jordanknott/taskcafe/internal/auth" | ||
"github.com/jordanknott/taskcafe/internal/db" | ||
"github.com/jordanknott/taskcafe/internal/logger" | ||
"github.com/jordanknott/taskcafe/internal/utils" | ||
"github.com/lithammer/fuzzysearch/fuzzy" | ||
hermes "github.com/matcornic/hermes/v2" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/vektah/gqlparser/v2/gqlerror" | ||
"golang.org/x/crypto/bcrypt" | ||
gomail "gopkg.in/mail.v2" | ||
) | ||
|
||
func (r *labelColorResolver) ID(ctx context.Context, obj *db.LabelColor) (uuid.UUID, error) { | ||
|
@@ -193,79 +191,11 @@ func (r *mutationResolver) InviteProjectMembers(ctx context.Context, input Invit | |
if err != nil { | ||
return &InviteProjectMembersPayload{Ok: false}, err | ||
} | ||
// send out invitation | ||
// add project invite entry | ||
// send out notification? | ||
h := hermes.Hermes{ | ||
// Optional Theme | ||
Product: hermes.Product{ | ||
// Appears in header & footer of e-mails | ||
Name: "Taskscafe", | ||
Link: "http://localhost:3333/", | ||
// Optional product logo | ||
Logo: "https://github.com/JordanKnott/taskcafe/raw/master/.github/taskcafe-full.png", | ||
}, | ||
} | ||
|
||
email := hermes.Email{ | ||
Body: hermes.Body{ | ||
Name: "Jordan Knott", | ||
Intros: []string{ | ||
"You have been invited to join Taskcafe", | ||
}, | ||
Actions: []hermes.Action{ | ||
{ | ||
Instructions: "To get started with Taskcafe, please click here:", | ||
Button: hermes.Button{ | ||
Color: "#7367F0", // Optional action button color | ||
TextColor: "#FFFFFF", | ||
Text: "Register your account", | ||
Link: "http://localhost:3000/register?confirmToken=" + confirmToken.ConfirmTokenID.String(), | ||
}, | ||
}, | ||
}, | ||
Outros: []string{ | ||
"Need help, or have questions? Just reply to this email, we'd love to help.", | ||
}, | ||
}, | ||
} | ||
|
||
// Generate an HTML email with the provided contents (for modern clients) | ||
emailBody, err := h.GenerateHTML(email) | ||
invite := utils.EmailInvite{To: *invitedMember.Email, FullName: *invitedMember.Email, ConfirmToken: confirmToken.ConfirmTokenID.String()} | ||
err = utils.SendEmailInvite(r.EmailConfig, invite) | ||
if err != nil { | ||
panic(err) // Tip: Handle error with something else than a panic ;) | ||
} | ||
emailBodyPlain, err := h.GeneratePlainText(email) | ||
if err != nil { | ||
panic(err) // Tip: Handle error with something else than a panic ;) | ||
} | ||
|
||
m := gomail.NewMessage() | ||
|
||
// Set E-Mail sender | ||
m.SetHeader("From", "[email protected]") | ||
|
||
// Set E-Mail receivers | ||
m.SetHeader("To", invitedUser.Email) | ||
|
||
// Set E-Mail subject | ||
m.SetHeader("Subject", "You have been invited to Taskcafe") | ||
|
||
// Set E-Mail body. You can set plain text or html with text/html | ||
m.SetBody("text/html", emailBody) | ||
m.AddAlternative("text/plain", emailBodyPlain) | ||
|
||
// Settings for SMTP server | ||
d := gomail.NewDialer("127.0.0.1", 11500, "[email protected]", "") | ||
|
||
// This is only needed when SSL/TLS certificate is not valid on server. | ||
// In production this should be set to false. | ||
d.TLSConfig = &tls.Config{InsecureSkipVerify: true} | ||
|
||
// Now send E-Mail | ||
if err := d.DialAndSend(m); err != nil { | ||
fmt.Println(err) | ||
panic(err) | ||
logger.New(ctx).WithError(err).Error("issue sending email") | ||
return &InviteProjectMembersPayload{Ok: false}, err | ||
} | ||
} else { | ||
return &InviteProjectMembersPayload{Ok: false}, err | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package utils | ||
|
||
import ( | ||
"crypto/tls" | ||
|
||
hermes "github.com/matcornic/hermes/v2" | ||
gomail "gopkg.in/mail.v2" | ||
) | ||
|
||
type EmailConfig struct { | ||
Host string | ||
Port int | ||
From string | ||
Username string | ||
Password string | ||
SiteURL string | ||
InsecureSkipVerify bool | ||
} | ||
|
||
type EmailInvite struct { | ||
ConfirmToken string | ||
FullName string | ||
To string | ||
} | ||
|
||
func SendEmailInvite(config EmailConfig, invite EmailInvite) error { | ||
h := hermes.Hermes{ | ||
Product: hermes.Product{ | ||
Name: "Taskscafe", | ||
Link: config.SiteURL, | ||
Logo: "https://github.com/JordanKnott/taskcafe/raw/master/.github/taskcafe-full.png", | ||
}, | ||
} | ||
|
||
email := hermes.Email{ | ||
Body: hermes.Body{ | ||
Name: invite.FullName, | ||
Intros: []string{ | ||
"You have been invited to join Taskcafe", | ||
}, | ||
Actions: []hermes.Action{ | ||
{ | ||
Instructions: "To get started with Taskcafe, please click here:", | ||
Button: hermes.Button{ | ||
Color: "#7367F0", // Optional action button color | ||
TextColor: "#FFFFFF", | ||
Text: "Register your account", | ||
Link: config.SiteURL + "/register?confirmToken=" + invite.ConfirmToken, | ||
}, | ||
}, | ||
}, | ||
Outros: []string{ | ||
"Need help, or have questions? Just reply to this email, we'd love to help.", | ||
}, | ||
}, | ||
} | ||
|
||
emailBody, err := h.GenerateHTML(email) | ||
if err != nil { | ||
return err | ||
} | ||
emailBodyPlain, err := h.GeneratePlainText(email) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
m := gomail.NewMessage() | ||
|
||
// Set E-Mail sender | ||
m.SetHeader("From", config.From) | ||
|
||
// Set E-Mail receivers | ||
m.SetHeader("To", invite.To) | ||
|
||
// Set E-Mail subject | ||
m.SetHeader("Subject", "You have been invited to Taskcafe") | ||
|
||
// Set E-Mail body. You can set plain text or html with text/html | ||
m.SetBody("text/html", emailBody) | ||
m.AddAlternative("text/plain", emailBodyPlain) | ||
|
||
// Settings for SMTP server | ||
d := gomail.NewDialer(config.Host, config.Port, config.Username, config.Password) | ||
|
||
// This is only needed when SSL/TLS certificate is not valid on server. | ||
// In production this should be set to false. | ||
d.TLSConfig = &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify} | ||
|
||
// Now send E-Mail | ||
if err := d.DialAndSend(m); err != nil { | ||
return err | ||
} | ||
return nil | ||
} |