commit 0017e12f942c741362ee5305930055a0de8fd494
parent d5f0f7daf9c4c382bb314c024cae1c98f8f139fe
Author: dwrz <dwrz@dwrz.net>
Date:   Fri,  2 Dec 2022 16:00:08 +0000
Add sgm command
Diffstat:
3 files changed, 130 insertions(+), 0 deletions(-)
diff --git a/cmd/sgm/config/config.go b/cmd/sgm/config/config.go
@@ -0,0 +1,47 @@
+package config
+
+import (
+	_ "embed"
+	"encoding/json"
+	"flag"
+	"fmt"
+)
+
+var (
+	//go:embed config.json
+	configuration []byte
+
+	attachment = flag.String("a", "", "attachment path")
+	from       = flag.String("f", "", "sender address")
+	subject    = flag.String("s", "", "subject")
+	text       = flag.String("m", "", "message text")
+	to         = flag.String("t", "", "recipient address, comma delimited")
+)
+
+type Config struct {
+	Attachment string
+	From       string
+	Pass       string
+	Subject    string
+	Text       string
+	To         string
+	User       string
+}
+
+func New() (*Config, error) {
+	flag.Parse()
+
+	var cfg = &Config{
+		Attachment: *attachment,
+		From:       *from,
+		Subject:    *subject,
+		Text:       *text,
+		To:         *to,
+	}
+	// Load the username and password from the embedded configuration.
+	if err := json.Unmarshal(configuration, cfg); err != nil {
+		return nil, fmt.Errorf("failed to parse config file: %v", err)
+	}
+
+	return cfg, nil
+}
diff --git a/cmd/sgm/config/config.json.template b/cmd/sgm/config/config.json.template
@@ -0,0 +1,4 @@
+{
+    "user": "",
+    "pass": ""
+}
diff --git a/cmd/sgm/main.go b/cmd/sgm/main.go
@@ -0,0 +1,79 @@
+package main
+
+import (
+	"encoding/base64"
+	"fmt"
+	"net/http"
+	"net/smtp"
+	"os"
+	"strings"
+
+	"code.dwrz.net/src/cmd/sgm/config"
+	"code.dwrz.net/src/pkg/gmail"
+	"code.dwrz.net/src/pkg/log"
+)
+
+func main() {
+	var l = log.New(os.Stderr)
+
+	// Get the configuration.
+	cfg, err := config.New()
+	if err != nil {
+		l.Error.Fatalf("failed to get config: %v", err)
+	}
+
+	// Compose email.
+	var str strings.Builder
+
+	fmt.Fprintf(&str, "From: %s\r\n", cfg.From)
+	fmt.Fprintf(&str, "To: %s\r\n", cfg.To)
+	fmt.Fprintf(&str, "Subject: %s\r\n", cfg.Subject)
+
+	str.WriteString("MIME-Version: 1.0\n")
+	str.WriteString("Content-Type: multipart/mixed; boundary=\"=-=-=\"\n")
+	str.WriteString("\n")
+	str.WriteString("--=-=-=\n")
+	str.WriteString("Content-Type: text/plain; format=flowed\n")
+	str.WriteString("\n")
+	str.WriteString("\n")
+	str.WriteString(cfg.Text)
+	str.WriteString("\n")
+	str.WriteString("--=-=-=\n")
+
+	// Add the attachment, if provided.
+	if cfg.Attachment != "" {
+		data, err := os.ReadFile(cfg.Attachment)
+		if err != nil {
+			l.Error.Fatalf("failed to open file: %v", err)
+		}
+
+		fmt.Fprintf(
+			&str,
+			"Content-Type: %s\n", http.DetectContentType(data),
+		)
+		fmt.Fprintf(
+			&str,
+			"Content-Disposition: attachment; filename=%s\n",
+			*&cfg.Attachment,
+		)
+		str.WriteString("Content-Transfer-Encoding: base64\n")
+		fmt.Fprintf(&str, "Content-Description: %s\n", cfg.Attachment)
+		str.WriteString("\n")
+		str.WriteString(base64.StdEncoding.EncodeToString([]byte(data)))
+		str.WriteString("--=-=-=\n")
+	}
+
+	// Send the email.
+	if err := smtp.SendMail(
+		gmail.Address,
+		&gmail.Auth{
+			Username: cfg.User,
+			Password: cfg.Pass,
+		},
+		cfg.From,
+		strings.Split(cfg.To, ","),
+		[]byte(str.String()),
+	); err != nil {
+		l.Error.Fatalf("failed to send email: %v", err)
+	}
+}