mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-21 17:21:09 +01:00
refactor: Add Outlook authentication support for sending emails
This commit is contained in:
@@ -14,4 +14,7 @@ type NotificationChannelV2 struct {
|
||||
WebhookUrl string `json:"webhook_url,omitempty" bson:"webhook_url,omitempty"`
|
||||
TelegramBotToken string `json:"telegram_bot_token,omitempty" bson:"telegram_bot_token,omitempty"`
|
||||
TelegramChatId string `json:"telegram_chat_id,omitempty" bson:"telegram_chat_id,omitempty"`
|
||||
OutlookTenantId string `json:"outlook_tenant_id,omitempty" bson:"outlook_tenant_id,omitempty"`
|
||||
OutlookClientId string `json:"outlook_client_id,omitempty" bson:"outlook_client_id,omitempty"`
|
||||
OutlookClientSecret string `json:"outlook_client_secret,omitempty" bson:"outlook_client_secret,omitempty"`
|
||||
}
|
||||
|
||||
@@ -13,6 +13,20 @@ import (
|
||||
)
|
||||
|
||||
func SendMail(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, to, cc, bcc, title, content string) error {
|
||||
// compatibility for different providers
|
||||
var auth *XOAuth2Auth
|
||||
if ch.Provider == ChannelMailProviderOutlook {
|
||||
token, err := getOutlookToken(ch.OutlookTenantId, ch.OutlookClientId, ch.OutlookClientSecret)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get outlook token: %v", err)
|
||||
return err
|
||||
}
|
||||
auth = &XOAuth2Auth{
|
||||
Username: ch.SMTPUsername,
|
||||
Token: token,
|
||||
}
|
||||
}
|
||||
|
||||
// config
|
||||
smtpConfig := smtpAuthentication{
|
||||
Server: ch.SMTPServer,
|
||||
@@ -42,7 +56,7 @@ func SendMail(s *models.NotificationSettingV2, ch *models.NotificationChannelV2,
|
||||
}
|
||||
|
||||
// send the email
|
||||
if err := send(smtpConfig, options, content, text); err != nil {
|
||||
if err := sendMail(smtpConfig, options, content, text, auth); err != nil {
|
||||
log.Errorf("failed to send email: %v", err)
|
||||
trace.PrintError(err)
|
||||
return err
|
||||
@@ -84,7 +98,7 @@ type sendOptions struct {
|
||||
}
|
||||
|
||||
// send email
|
||||
func send(smtpConfig smtpAuthentication, options sendOptions, htmlBody string, txtBody string) error {
|
||||
func sendMail(smtpConfig smtpAuthentication, options sendOptions, htmlBody string, txtBody string, auth *XOAuth2Auth) error {
|
||||
if smtpConfig.Server == "" {
|
||||
return errors.New("SMTP server config is empty")
|
||||
}
|
||||
@@ -132,6 +146,9 @@ func send(smtpConfig smtpAuthentication, options sendOptions, htmlBody string, t
|
||||
m.AddAlternative("text/html", htmlBody)
|
||||
|
||||
d := gomail.NewDialer(smtpConfig.Server, smtpConfig.Port, smtpConfig.SMTPUser, smtpConfig.SMTPPassword)
|
||||
if auth != nil {
|
||||
d.Auth = auth
|
||||
}
|
||||
|
||||
return d.DialAndSend(m)
|
||||
}
|
||||
|
||||
55
core/notification/mail_outlook.go
Normal file
55
core/notification/mail_outlook.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func getOutlookToken(tenantID, clientID, clientSecret string) (string, error) {
|
||||
url := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantID)
|
||||
data := map[string]string{
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": clientID,
|
||||
"client_secret": clientSecret,
|
||||
"scope": "https://outlook.office365.com/.default",
|
||||
}
|
||||
|
||||
formData := ""
|
||||
for key, value := range data {
|
||||
if formData != "" {
|
||||
formData += "&"
|
||||
}
|
||||
formData += fmt.Sprintf("%s=%s", key, value)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBufferString(formData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if token, ok := result["access_token"].(string); ok {
|
||||
return token, nil
|
||||
}
|
||||
return "", fmt.Errorf("no access token found")
|
||||
}
|
||||
21
core/notification/oauth2_auth.go
Normal file
21
core/notification/oauth2_auth.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
type XOAuth2Auth struct {
|
||||
Username, Token string
|
||||
}
|
||||
|
||||
func (a *XOAuth2Auth) Start(_ *smtp.ServerInfo) (string, []byte, error) {
|
||||
return "XOAUTH2", []byte("user=" + a.Username + "\x01auth=Bearer " + a.Token + "\x01\x01"), nil
|
||||
}
|
||||
|
||||
func (a *XOAuth2Auth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||
if more {
|
||||
return nil, fmt.Errorf("unexpected server challenge: %s", fromServer)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
Reference in New Issue
Block a user