diff --git a/cmd/inline.go b/cmd/inline.go index 40591bd..1556e83 100644 --- a/cmd/inline.go +++ b/cmd/inline.go @@ -1,31 +1,27 @@ package cmd import ( - "fmt" - + "log" "github.com/spf13/cobra" + "git.dafu.dev/dafu/gomailer/pkg" ) // inlineCmd represents the send command var inlineCmd = &cobra.Command{ - Use: "inline", - Short: "Inline styles in template without sending", - Long: ``, + Short: "Inline styles in template file without sending", + Long: `Inlines styles in given template and saves it to *_inlined.html`, + Args: cobra.MinimumNArgs(1), + Use: "inline [flags] [...template.html]", Run: func(cmd *cobra.Command, args []string) { - fmt.Println("send called") + log.Printf("Templates: %v", args) + + for _, arg := range args { + gomailer.Inline(arg) + + } }, } func init() { rootCmd.AddCommand(inlineCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // inlineCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // inlineCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/root.go b/cmd/root.go index a90816c..67eedaa 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,22 +1,28 @@ package cmd import ( - "fmt" + "log" "os" + "git.dafu.dev/dafu/gomailer/pkg" "github.com/spf13/cobra" "github.com/spf13/viper" ) var cfgFile string +var Cfg Config + +type Config struct { + mailserver gomailer.MailServer `mapstructure:"mailserver"` + mailsettings gomailer.MailSettings `mapstructure:"mailsettings"` +} + // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "gomailer", Short: "use it to test email templates", - Long: ``, - // Uncomment the following line if your bare application - // has an action associated with it: + Long: ``, // Run: func(cmd *cobra.Command, args []string) { }, } @@ -31,38 +37,61 @@ func Execute() { func init() { cobra.OnInitialize(initConfig) - - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - + rootCmd.CompletionOptions.DisableDefaultCmd = true rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.gomailer.yaml)") - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // rootCmd.PersistentFlags().StringVarP(&Template, "template", "t", "", "Path to html template") + // viper.BindPFlag("template", rootCmd.PersistentFlags().Lookup("template")) } // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { - // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { - // Find home directory. - home, err := os.UserHomeDir() - cobra.CheckErr(err) - - // Search config in home directory with name ".gomailer" (without extension). - viper.AddConfigPath(home) + viper.AddConfigPath(".") viper.SetConfigType("yaml") - viper.SetConfigName(".gomailer") + viper.SetConfigName("gomailer") } viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { - fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + mserver := &gomailer.MailServer{} + msettings := &gomailer.MailSettings{} + + if err := viper.UnmarshalKey("mailserver", mserver); err != nil { + log.Fatal(err) + } + if err := viper.UnmarshalKey("mailsettings", msettings); err != nil { + log.Fatal(err) + } + + Cfg.mailserver = *mserver + Cfg.mailsettings = *msettings + } else { + generateDefaultConfig() } } + +func generateDefaultConfig() { + // mailserver + viper.SetDefault("mailserver.Port", 25) + viper.SetDefault("mailserver.Host", "localhost") + viper.SetDefault("mailserver.Username", "user") + viper.SetDefault("mailserver.Password", "pass") + viper.SetDefault("mailserver.Tls", "notls|mandatory") + viper.SetDefault("mailserver.Authtype", "nologin|plain|login|cram-md5") + viper.SetDefault("mailserver.Skipverify", false) + // mailsettings + viper.SetDefault("mailsettings.Subject", "subject") + viper.SetDefault("mailsettings.From", "from@local") + viper.SetDefault("mailsettings.To", "to@local") + viper.SetDefault("mailsettings.Cc", "cc@local") + viper.SetDefault("mailsettings.Template", "email.html") + viper.SetDefault("mailsettings.Inline", true) + + viper.SafeWriteConfig() + log.Printf("Writing default config file: " + viper.ConfigFileUsed()) +} diff --git a/cmd/sendmail.go b/cmd/sendmail.go index 64c11f4..d7accce 100644 --- a/cmd/sendmail.go +++ b/cmd/sendmail.go @@ -1,20 +1,11 @@ package cmd import ( - ht "html/template" - "log" - "os" + "git.dafu.dev/dafu/gomailer/pkg" "github.com/spf13/cobra" - "github.com/vanng822/go-premailer/premailer" - "github.com/wneessen/go-mail" ) -var help bool -var inline bool -var template string -var output string - // sendmailCmd represents the sendmail command var sendmailCmd = &cobra.Command{ Use: "sendmail", @@ -24,71 +15,14 @@ var sendmailCmd = &cobra.Command{ sendmail.`, Run: func(cmd *cobra.Command, args []string) { - prem, err := premailer.NewPremailerFromFile(template, premailer.NewOptions()) - if err != nil { - log.Fatal(err) - } - - html, err := prem.Transform() - if err != nil { - log.Fatal(err) - } - - f, err := os.Create(template + "_inlined.html") - defer f.Close() - f.WriteString(html) - f.Sync() - - // fmt.Println(html) - - m := mail.NewMsg() - if err := m.From("sender@domain.local"); err != nil { - log.Fatalf("failed to set From address: %s", err) - } - if err := m.To("recipient@domain.local"); err != nil { - log.Fatalf("failed to set To address: %s", err) - } - m.Subject("Subject") - - htpl, err := ht.New("htmltpl").Parse(html) - if err != nil { - log.Fatalf("failed to parse text template: %s", err) - } - - // embedd images - for _, val := range findSrcInHtml(html) { - log.Println("embedding: " + val) - m.EmbedFile(val) - } - - m.SetBodyHTMLTemplate(htpl, nil) - - c, err := mail.NewClient("localhost", mail.WithPort(25), mail.WithTLSPolicy(mail.NoTLS)) - if err != nil { - log.Fatalf("failed to create mail client: %s", err) - } - if err := c.DialAndSend(m); err != nil { - log.Fatalf("failed to send mail: %s", err) - } + gomailer.SendMail(Cfg.mailsettings, Cfg.mailserver) }, } - - func init() { rootCmd.AddCommand(sendmailCmd) - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // sendmailCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - sendmailCmd.Flags().BoolVar(&help, "test", false, "Help message for sendmail") - sendmailCmd.Flags().BoolVarP(&inline, "inline", "i", false, "Inline css") - sendmailCmd.Flags().StringVarP(&template, "template", "t", "", "Path to html template") - sendmailCmd.Flags().StringVarP(&output, "output", "o", "", "Path to save inlined html") + // sendmailCmd.Flags().BoolVar(&help, "test", false, "Help message for sendmail") + // sendmailCmd.Flags().BoolVarP(&inline, "inline", "i", false, "Inline css") } diff --git a/cmd/utils.go b/cmd/utils.go deleted file mode 100644 index 3ceae5b..0000000 --- a/cmd/utils.go +++ /dev/null @@ -1,40 +0,0 @@ -package cmd - -import ( - "log" - "strings" - - "golang.org/x/net/html" -) - -func findSrcInHtml(doc string) []string { - var results []string - reader := strings.NewReader(doc) - if document, err := html.Parse(reader); err == nil { - - var parser func(*html.Node) - parser = func(n *html.Node) { - if n.Type == html.ElementNode && n.Data == "img" { - - var imgSrcUrl string - - for _, element := range n.Attr { - if element.Key == "src" { - imgSrcUrl = element.Val - log.Print("found image:" + imgSrcUrl) - results = append(results, imgSrcUrl) - } - } - } - - for c := n.FirstChild; c != nil; c = c.NextSibling { - parser(c) - } - - } - parser(document) - } else { - log.Panicln("Parse html error", err) - } - return results -} diff --git a/go.mod b/go.mod index ac2bb2b..90287a2 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module git.dafu.dev/gomailer +module git.dafu.dev/dafu/gomailer go 1.20 @@ -7,6 +7,7 @@ require ( github.com/spf13/viper v1.15.0 github.com/vanng822/go-premailer v1.20.1 github.com/wneessen/go-mail v0.3.9 + golang.org/x/net v0.9.0 ) require ( @@ -25,9 +26,8 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/vanng822/css v1.0.1 // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 04fd393..467f915 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,7 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -60,6 +61,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -101,6 +103,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -134,8 +137,10 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -144,9 +149,11 @@ github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvI github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= @@ -170,6 +177,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -264,8 +272,8 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -320,8 +328,8 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -329,8 +337,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -474,6 +482,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= diff --git a/main.go b/main.go index 4bd0203..70fefa6 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,6 @@ -/* -Copyright © 2023 NAME HERE - -*/ package main -import "git.dafu.dev/gomailer/cmd" +import "git.dafu.dev/dafu/gomailer/cmd" func main() { cmd.Execute() diff --git a/pkg/inline.go b/pkg/inline.go new file mode 100644 index 0000000..a394ebd --- /dev/null +++ b/pkg/inline.go @@ -0,0 +1,84 @@ +package gomailer + +import ( + "log" + "os" + "path" + "strings" + "golang.org/x/net/html" + "github.com/vanng822/go-premailer/premailer" +) + +func Inline(arg string) { + out := LoadTemplate(arg, true) + + dir := path.Dir(arg) + ext := path.Ext(arg) + base := strings.ReplaceAll(path.Base(arg), ext, "") + output_file := path.Join(dir, base+"_inlined"+ext) + log.Printf("Template: %s -> %s", arg, output_file) + + f, err := os.Create(output_file) + if err != nil { + log.Fatal("error inlining html: " + err.Error()) + } + _, err = f.WriteString(out) + + if err != nil { + log.Fatal("error inlining html: " + err.Error()) + } +} + +func LoadTemplate(template string, inline bool) (string) { + rawhtml, err := os.ReadFile(template) + if err != nil { + log.Fatal("error loading template: " + err.Error()) + } + + if inline { + prem, err := premailer.NewPremailerFromBytes(rawhtml, premailer.NewOptions()) + if err != nil { + log.Fatal("error inlining html: " + err.Error()) + } + + inlinehtml, err := prem.Transform() + if err != nil { + log.Fatal("error transforming html: " + err.Error()) + } + return inlinehtml + } + + return string(rawhtml) +} + +func FindSrcInHtml(doc string) []string { + var results []string + reader := strings.NewReader(doc) + if document, err := html.Parse(reader); err == nil { + + var parser func(*html.Node) + parser = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "img" { + + var imgSrcUrl string + + for _, element := range n.Attr { + if element.Key == "src" { + imgSrcUrl = element.Val + log.Print("found image:" + imgSrcUrl) + results = append(results, imgSrcUrl) + } + } + } + + for c := n.FirstChild; c != nil; c = c.NextSibling { + parser(c) + } + + } + parser(document) + } else { + log.Fatalln("Parse html error", err) + } + return results +} diff --git a/pkg/mail.go b/pkg/mail.go new file mode 100644 index 0000000..9e311d2 --- /dev/null +++ b/pkg/mail.go @@ -0,0 +1,112 @@ +package gomailer + +import ( + "crypto/tls" + "github.com/wneessen/go-mail" + ht "html/template" + "log" +) + +type MailSettings struct { + Subject string + From string + To string + Cc string + Inline bool + Template string +} + +type MailServer struct { + Port int + Host string + Username string + Password string + Tls string + Authtype string + Skipverify bool +} + +func SendMail(mailsettings MailSettings, serversettings MailServer) { + html := LoadTemplate(mailsettings.Template, true) + + m := mail.NewMsg() + if err := m.From(mailsettings.From); err != nil { + log.Fatalf("failed to set From address: %s", err) + } + if err := m.To(mailsettings.From); err != nil { + log.Fatalf("failed to set To address: %s", err) + } + + m.Subject(mailsettings.Subject) + + htpl, err := ht.New("htmltpl").Parse(html) + if err != nil { + log.Fatalf("failed to parse text template: %s", err) + } + + // embedd images + for _, val := range FindSrcInHtml(html) { + log.Println("Embedding: " + val) + m.EmbedFile(val) + } + + // set template + m.SetBodyHTMLTemplate(htpl, nil) + + // generate client + c, err := getClient(serversettings) + if err != nil { + log.Fatalf("failed to create mail client: %s", err) + } + + // send mail + if err := c.DialAndSend(m); err != nil { + log.Fatalf("failed to send mail: %s", err) + } +} + +func getClient(config MailServer) (*mail.Client, error) { + var authType mail.SMTPAuthType + switch config.Authtype { + case "plain": + authType = mail.SMTPAuthPlain + case "login": + authType = mail.SMTPAuthLogin + case "cram-md5": + authType = mail.SMTPAuthCramMD5 + } + + // tlsPolicy := mail.TLSOpportunistic + tlsPolicy := mail.DefaultTLSPolicy + switch config.Tls { + case "notls": + tlsPolicy = mail.NoTLS + case "mandatory": + tlsPolicy = mail.TLSMandatory + } + + opts := []mail.Option{ + mail.WithPort(config.Port), + mail.WithTLSPolicy(tlsPolicy), + mail.WithTLSConfig(&tls.Config{ + InsecureSkipVerify: config.Skipverify, + }), + } + + if config.Authtype != "nologin" { + opts = append(opts, mail.WithSMTPAuth(authType)) + } + + if config.Username != "" { + opts = append(opts, mail.WithUsername(config.Username)) + } + + if config.Password != "" { + opts = append(opts, mail.WithPassword(config.Password)) + } + + return mail.NewClient( + config.Host, + opts..., + ) +}