Select Git revision
runnable-fileoperation.go
runnable-mail.go 4.19 KiB
// Copyright 2023 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0
package jobqueue
import (
"context"
"fmt"
"net/smtp"
"sync"
)
func NewMailRunnableFromMap(data map[string]interface{}) (*MailRunnable, error) {
to, ok := data["to"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid To: %v", ErrInvalidData, data["to"])
}
from, ok := data["from"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid From: %v", ErrInvalidData, data["from"])
}
subject, ok := data["subject"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Subject: %v", ErrInvalidData, data["subject"])
}
body, ok := data["l"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Body: %v", ErrInvalidData, data["body"])
}
server, ok := data["server"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Server: %v", ErrInvalidData, data["server"])
}
port, ok := data["port"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Port: %v", ErrInvalidData, data["port"])
}
username, ok := data["username"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Username: %v", ErrInvalidData, data["username"])
}
password, ok := data["password"].(string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Password: %v", ErrInvalidData, data["password"])
}
headers, ok := data["headers"].(map[string]string)
if !ok {
return nil, fmt.Errorf("%w: Invalid Headers: %v", ErrInvalidData, data["headers"])
}
return &MailRunnable{
To: to,
From: from,
Subject: subject,
Body: body,
Server: server,
Port: port,
Username: username,
Password: password,
Headers: headers,
}, nil
}
// MailResult is a result of a email
type MailResult struct {
Sent bool
ServerReply string
SmtpStatusCode uint
}
func (m *MailResult) GetResult() string {
return fmt.Sprintf("Sent: %t\n\nServerReply: %s\n\nSmtpStatusCode: %d", m.Sent, m.ServerReply, m.SmtpStatusCode)
}
func (m *MailResult) GetError() (string, int) {
if !m.Sent {
return fmt.Sprintf("Sent: %t\n\nServerReply: %s\n\nSmtpStatusCode: %d", m.Sent, m.ServerReply, m.SmtpStatusCode), 1
}
return "", 0
}
type MailRunnable struct {
To string
From string
Subject string
Body string
Server string
Port string
Username string
Password string
Headers map[string]string
mu sync.Mutex
}
func (m *MailRunnable) Run(_ context.Context) (RunResult[MailResult], error) {
smtpServer := m.Server + ":" + m.Port
// Connect to the remote SMTP server.
client, err := smtp.Dial(smtpServer)
if err != nil {
return RunResult[MailResult]{Status: ResultStatusFailed}, err
}
if client != nil {
defer client.Close()
}
if m.Username != "" && m.Password != "" {
if err := client.Auth(smtp.PlainAuth("", m.Username, m.Password, m.Server)); err != nil {
return RunResult[MailResult]{Status: ResultStatusFailed}, err
}
}
// To && From.
if err := client.Mail(m.From); err != nil {
return RunResult[MailResult]{Status: ResultStatusFailed}, err
}
if err := client.Rcpt(m.To); err != nil {
return RunResult[MailResult]{Status: ResultStatusFailed}, err
}
// Headers and Data.
writer, err := client.Data()
if err != nil {
return RunResult[MailResult]{Status: ResultStatusFailed}, err
}
headers := "From: " + m.From + "\r\n"
headers += "To: " + m.To + "\r\n"
headers += "Subject: " + m.Subject + "\r\n"
for key, value := range m.Headers {
headers += key + ": " + value + "\r\n"
}
_, err = writer.Write([]byte(headers + "\r\n" + m.Body))
if err != nil {
return RunResult[MailResult]{Status: ResultStatusFailed}, err
}
_ = writer.Close()
// Quit and get the SMTP status code.
smtpStatusCode, _ := client.Text.Cmd("QUIT")
return RunResult[MailResult]{Status: ResultStatusSuccess, Data: MailResult{Sent: true, SmtpStatusCode: smtpStatusCode}}, nil
}
func (m *MailRunnable) GetType() string {
return "mail"
}
func (m *MailRunnable) GetPersistence() RunnableImport {
m.mu.Lock()
defer m.mu.Unlock()
data := JSONMap{
"to": m.To,
"from": m.From,
"subject": m.Subject,
"body": m.Body,
"server": m.Server,
"port": m.Port,
"username": m.Username,
"password": m.Password,
"headers": m.Headers,
}
return RunnableImport{
Type: m.GetType(),
Data: data,
}
}