Skip to content

Commit

Permalink
fix: address various issues with email receivers
Browse files Browse the repository at this point in the history
Signed-off-by: Donnie Adams <[email protected]>
  • Loading branch information
thedadams committed Jan 7, 2025
1 parent b5f66dc commit 4ef2c5f
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 26 deletions.
2 changes: 1 addition & 1 deletion apiclient/types/emailreceiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type EmailReceiver struct {
type EmailReceiverManifest struct {
Name string `json:"name"`
Description string `json:"description"`
User string `json:"user,omitempty"`
Alias string `json:"alias,omitempty"`
Workflow string `json:"workflow"`
AllowedSenders []string `json:"allowedSenders,omitempty"`
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/alias/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
kclient "sigs.k8s.io/controller-runtime/pkg/client"
)

func Get(ctx context.Context, c kclient.Client, obj v1.Aliasable, namespace string, name string) error {
func Get(ctx context.Context, c kclient.Client, obj v1.Aliasable, namespace, name string) error {
var errLookup error
if namespace == "" {
gvk, err := c.GroupVersionKindFor(obj.(kclient.Object))
Expand Down
10 changes: 8 additions & 2 deletions pkg/api/handlers/emailreceiver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package handlers

import (
"fmt"

"github.com/obot-platform/obot/apiclient/types"
"github.com/obot-platform/obot/pkg/alias"
"github.com/obot-platform/obot/pkg/api"
Expand Down Expand Up @@ -90,8 +92,12 @@ func convertEmailReceiver(emailReceiver v1.EmailReceiver, hostname string) *type
EmailReceiverManifest: manifest,
AddressAssigned: aliasAssigned,
}
if hostname != "" && er.AddressAssigned != nil && *er.AddressAssigned {
er.EmailAddress = emailReceiver.Spec.User + "@" + hostname
if hostname != "" {
name := emailReceiver.Name
if er.AddressAssigned != nil && *er.AddressAssigned {
name = er.Alias
}
er.EmailAddress = fmt.Sprintf("%s@%s", name, hostname)
}
return er
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/handlers/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ func (t *TaskHandler) updateEmail(req api.Context, workflow *v1.Workflow, task t
},
Spec: v1.EmailReceiverSpec{
EmailReceiverManifest: types.EmailReceiverManifest{
User: workflow.Spec.Manifest.Alias,
Alias: workflow.Spec.Manifest.Alias,
Workflow: workflow.Name,
},
ThreadName: workflow.Spec.ThreadName,
Expand Down
11 changes: 11 additions & 0 deletions pkg/services/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log/slog"
"net/url"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -186,6 +187,9 @@ func New(ctx context.Context, config Config) (*Services, error) {
if config.UIHostname == "" {
config.UIHostname = config.Hostname
}
if config.EmailServerName == "" {
config.EmailServerName = config.UIHostname
}

if strings.HasPrefix(config.Hostname, "localhost") || strings.HasPrefix(config.Hostname, "127.0.0.1") {
config.Hostname = "http://" + config.Hostname
Expand All @@ -195,6 +199,13 @@ func New(ctx context.Context, config Config) (*Services, error) {
if !strings.HasPrefix(config.UIHostname, "http") {
config.UIHostname = "https://" + config.UIHostname
}
// Ensure that the email server name is just a hostname
u, err := url.Parse(config.EmailServerName)
if err != nil {
return nil, fmt.Errorf("invalid email server name: %w", err)
}

config.EmailServerName = u.Hostname()

c, err := newGPTScript(ctx, config.WorkspaceTool, config.DatasetsTool, config.ToolRegistry)
if err != nil {
Expand Down
38 changes: 21 additions & 17 deletions pkg/smtp/smtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ func (s *Server) handler(_ net.Addr, from string, to []string, data []byte) erro
continue
}

ns, name, ok := strings.Cut(name, ".")
if !ok {
log.Infof("Skipping mail for %s: no namespace found", toAddr.Address)
name, ns, _ := strings.Cut(name, "+")
if ns == "" {
ns = system.DefaultNamespace
}

var emailReceiver v1.EmailReceiver
if err := alias.Get(s.ctx, s.c, &emailReceiver, ns, name); apierror.IsNotFound(err) {
if err = alias.Get(s.ctx, s.c, &emailReceiver, ns, name); apierror.IsNotFound(err) {
log.Infof("Skipping mail for %s: no receiver found", toAddr.Address)
continue
} else if err != nil {
Expand All @@ -106,15 +106,7 @@ func (s *Server) handler(_ net.Addr, from string, to []string, data []byte) erro
continue
}

if len(emailReceiver.Spec.AllowedSenders) > 0 {
for _, allowedSender := range emailReceiver.Spec.AllowedSenders {
if allowedSender == fromAddress.Address {
break
}
}
}

if err := s.dispatchEmail(emailReceiver, body, message); err != nil {
if err = s.dispatchEmail(emailReceiver, body, message, from, to); err != nil {
return fmt.Errorf("dispatch email: %w", err)
}
}
Expand Down Expand Up @@ -158,6 +150,18 @@ func getBody(message *mail.Message) (string, error) {
html = string(d)
}
}
} else if strings.HasPrefix(mediaType, "text/plain") || strings.HasPrefix(mediaType, "text/html") {
d, err := io.ReadAll(message.Body)
if err != nil {
return "", err
}
if message.Header.Get("Content-Transfer-Encoding") == "base64" {
d, err = base64.StdEncoding.DecodeString(string(d))
if err != nil {
return "", err
}
}
html = string(d)
}

if html != "" {
Expand All @@ -167,7 +171,7 @@ func getBody(message *mail.Message) (string, error) {
return "", fmt.Errorf("failed to find text/plain body: %s", mediaType)
}

func (s *Server) dispatchEmail(email v1.EmailReceiver, body string, message *mail.Message) error {
func (s *Server) dispatchEmail(email v1.EmailReceiver, body string, message *mail.Message, from, to string) error {
var input struct {
Type string `json:"type"`
From string `json:"from"`
Expand All @@ -177,8 +181,8 @@ func (s *Server) dispatchEmail(email v1.EmailReceiver, body string, message *mai
}

input.Type = "email"
input.From = message.Header.Get("From")
input.To = message.Header.Get("To")
input.From = from
input.To = to
input.Subject = message.Header.Get("Subject")
input.Body = body

Expand All @@ -188,7 +192,7 @@ func (s *Server) dispatchEmail(email v1.EmailReceiver, body string, message *mai
}

var workflow v1.Workflow
if err := alias.Get(s.ctx, s.c, &workflow, email.Namespace, email.Spec.Workflow); err != nil {
if err = alias.Get(s.ctx, s.c, &workflow, email.Namespace, email.Spec.Workflow); err != nil {
return err
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/storage/apis/otto.otto8.ai/v1/emailaddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (in *EmailReceiver) FieldNames() []string {
}

func (in *EmailReceiver) GetAliasName() string {
return in.Spec.EmailReceiverManifest.User
return in.Spec.EmailReceiverManifest.Alias
}

func (in *EmailReceiver) SetAssigned(assigned bool) {
Expand All @@ -64,7 +64,7 @@ func (in *EmailReceiver) SetObservedGeneration(gen int64) {
func (*EmailReceiver) GetColumns() [][]string {
return [][]string{
{"Name", "Name"},
{"User", "Spec.User"},
{"Alias", "Spec.Alias"},
{"Workflow", "Spec.Workflow"},
{"Created", "{{ago .CreationTimestamp}}"},
{"Description", "Spec.Description"},
Expand Down
4 changes: 2 additions & 2 deletions pkg/storage/openapi/generated/openapi_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4ef2c5f

Please sign in to comment.