2023-06-14 06:31:19 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2023-06-15 16:45:14 +03:00
|
|
|
"fmt"
|
2023-06-15 17:30:20 +03:00
|
|
|
"io"
|
2023-06-14 06:31:19 +03:00
|
|
|
"os"
|
2023-06-15 17:59:25 +03:00
|
|
|
"strings"
|
2023-06-14 06:31:19 +03:00
|
|
|
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
2023-06-15 17:30:20 +03:00
|
|
|
"github.com/resendlabs/resend-go"
|
2023-06-14 06:31:19 +03:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
2023-06-15 16:45:14 +03:00
|
|
|
const RESEND_API_KEY = "RESEND_API_KEY"
|
2023-06-15 17:30:20 +03:00
|
|
|
const RESEND_FROM = "RESEND_FROM"
|
|
|
|
|
|
|
|
var (
|
|
|
|
from string
|
|
|
|
to []string
|
|
|
|
subject string
|
|
|
|
body string
|
|
|
|
attachments []string
|
|
|
|
)
|
2023-06-15 16:45:14 +03:00
|
|
|
|
2023-06-14 06:31:19 +03:00
|
|
|
var rootCmd = &cobra.Command{
|
|
|
|
Use: "email",
|
|
|
|
Short: "email is a command line interface for sending emails.",
|
|
|
|
Long: `email is a command line interface for sending emails.`,
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
2023-06-15 17:30:20 +03:00
|
|
|
if hasStdin() {
|
|
|
|
b, err := io.ReadAll(os.Stdin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
body = string(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(to) > 0 && from != "" && subject != "" && body != "" {
|
|
|
|
err := sendEmail(to, from, subject, body, attachments)
|
|
|
|
if err != nil {
|
2023-06-15 17:52:27 +03:00
|
|
|
cmd.SilenceUsage = true
|
|
|
|
cmd.SilenceErrors = true
|
|
|
|
fmt.Println(errorStyle.Render(err.Error()))
|
2023-06-15 17:30:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2023-06-15 18:03:14 +03:00
|
|
|
fmt.Print(emailSummary(to, subject))
|
2023-06-15 17:30:20 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
p := tea.NewProgram(NewModel(resend.SendEmailRequest{
|
|
|
|
From: from,
|
|
|
|
To: to,
|
|
|
|
Subject: subject,
|
|
|
|
Text: body,
|
|
|
|
}))
|
2023-06-15 17:59:25 +03:00
|
|
|
m, err := p.Run()
|
2023-06-14 06:31:19 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-15 17:59:25 +03:00
|
|
|
mm := m.(Model)
|
2023-06-15 18:04:38 +03:00
|
|
|
if !mm.abort {
|
|
|
|
fmt.Print(emailSummary(strings.Split(mm.To.Value(), TO_SEPARATOR), mm.Subject.Value()))
|
|
|
|
}
|
2023-06-14 06:31:19 +03:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-06-15 17:30:20 +03:00
|
|
|
// hasStdin returns whether there is data in stdin.
|
|
|
|
func hasStdin() bool {
|
|
|
|
stat, err := os.Stdin.Stat()
|
|
|
|
return err == nil && (stat.Mode()&os.ModeCharDevice) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2023-06-15 18:27:20 +03:00
|
|
|
rootCmd.Flags().StringSliceVar(&to, "bcc", []string{}, "BCC recipients")
|
|
|
|
rootCmd.Flags().StringSliceVar(&to, "cc", []string{}, "CC recipients")
|
2023-06-15 17:30:20 +03:00
|
|
|
rootCmd.Flags().StringSliceVarP(&attachments, "attach", "a", []string{}, "Email's attachments")
|
2023-06-15 18:27:20 +03:00
|
|
|
rootCmd.Flags().StringSliceVarP(&to, "to", "t", []string{}, "Recipients")
|
|
|
|
rootCmd.Flags().StringVarP(&body, "body", "b", "", "Email's contents")
|
|
|
|
rootCmd.Flags().StringVarP(&from, "from", "f", os.Getenv(RESEND_FROM), "Email's sender "+commentStyle.Render("($RESEND_FROM)"))
|
2023-06-15 17:30:20 +03:00
|
|
|
rootCmd.Flags().StringVarP(&subject, "subject", "s", "", "Email's subject")
|
|
|
|
}
|
|
|
|
|
2023-06-14 06:31:19 +03:00
|
|
|
func main() {
|
2023-06-15 16:45:14 +03:00
|
|
|
key := os.Getenv(RESEND_API_KEY)
|
|
|
|
if key == "" {
|
|
|
|
fmt.Printf("\n %s %s %s\n\n", errorHeaderStyle.String(), inlineCodeStyle.Render(RESEND_API_KEY), "environment variable is required.")
|
|
|
|
fmt.Printf(" %s %s\n\n", commentStyle.Render("You can grab one at"), linkStyle.Render("https://resend.com"))
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2023-06-14 06:31:19 +03:00
|
|
|
err := rootCmd.Execute()
|
|
|
|
if err != nil {
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|