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"`
|
WebhookUrl string `json:"webhook_url,omitempty" bson:"webhook_url,omitempty"`
|
||||||
TelegramBotToken string `json:"telegram_bot_token,omitempty" bson:"telegram_bot_token,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"`
|
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 {
|
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
|
// config
|
||||||
smtpConfig := smtpAuthentication{
|
smtpConfig := smtpAuthentication{
|
||||||
Server: ch.SMTPServer,
|
Server: ch.SMTPServer,
|
||||||
@@ -42,7 +56,7 @@ func SendMail(s *models.NotificationSettingV2, ch *models.NotificationChannelV2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send the email
|
// 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)
|
log.Errorf("failed to send email: %v", err)
|
||||||
trace.PrintError(err)
|
trace.PrintError(err)
|
||||||
return err
|
return err
|
||||||
@@ -84,7 +98,7 @@ type sendOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send email
|
// 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 == "" {
|
if smtpConfig.Server == "" {
|
||||||
return errors.New("SMTP server config is empty")
|
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)
|
m.AddAlternative("text/html", htmlBody)
|
||||||
|
|
||||||
d := gomail.NewDialer(smtpConfig.Server, smtpConfig.Port, smtpConfig.SMTPUser, smtpConfig.SMTPPassword)
|
d := gomail.NewDialer(smtpConfig.Server, smtpConfig.Port, smtpConfig.SMTPUser, smtpConfig.SMTPPassword)
|
||||||
|
if auth != nil {
|
||||||
|
d.Auth = auth
|
||||||
|
}
|
||||||
|
|
||||||
return d.DialAndSend(m)
|
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