first commit

This commit is contained in:
Timofey.Kovalev
2025-10-14 10:35:42 +03:00
commit 9972005cb5
9 changed files with 386 additions and 0 deletions

54
internal/config/config.go Normal file
View File

@ -0,0 +1,54 @@
package config
import (
"errors"
"fmt"
"os"
"path"
"strings"
"github.com/go-yaml/yaml"
)
func LoadConfig(filePath string) (*Config, error) {
cfg := Config{}
isDefaultConfig := filePath == DefaultConfigPath
if strings.HasPrefix(filePath, "~") {
if v, ok := os.LookupEnv("HOME"); ok {
filePath = strings.Replace(filePath, "~", v, 1)
} else {
return nil, fmt.Errorf("$HOME not set in env")
}
}
if _, err := os.Stat(filePath); errors.Is(err, os.ErrNotExist) {
if isDefaultConfig {
dir, _ := path.Split(filePath)
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
return nil, err
}
err = os.WriteFile(filePath, []byte(DefaultConfig), 0644)
if err != nil {
return nil, err
}
}
return &cfg, nil
}
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(data), &cfg)
if err != nil {
return nil, err
}
return &cfg, nil
}

15
internal/config/const.go Normal file
View File

@ -0,0 +1,15 @@
package config
const DefaultConfigPath = "~/.config/qmail/main.yaml"
const DefaultConfig = `
servers:
# - name: s1
# host: localhost
# port: 587
# use-tls: true
# auth:
# login: login
# password: password
`

24
internal/config/struct.go Normal file
View File

@ -0,0 +1,24 @@
package config
type Auth struct {
Login string `yaml:"login"`
Password string `yaml:"password"`
}
type Server struct {
Name string `yaml:"name"`
Host string `yaml:"host"`
Port uint16 `yaml:"port"`
From string `yaml:"from"`
To string `yaml:"to"`
UseTLS bool `yaml:"use-tls"`
Auth *Auth `yaml:"auth"`
}
type Config struct {
Servers []Server
}

99
internal/mail/mail.go Normal file
View File

@ -0,0 +1,99 @@
package mail
import (
"crypto/tls"
"fmt"
"net/smtp"
"qmail/internal/config"
)
func SendMail(server *config.Server, from string, to []string, data []byte) error {
fmt.Println("Send...")
if server.Host == "" || server.Port == 0 {
return fmt.Errorf("invalide server host or port")
}
fmt.Printf("Dial:%s:%d\n", server.Host, server.Port)
// Connect to the remote SMTP server.
c, err := smtp.Dial(fmt.Sprintf("%s:%d", server.Host, server.Port))
if err != nil {
return err
}
fmt.Println("omg")
if server.UseTLS {
fmt.Println("start TLS")
err = c.StartTLS(&tls.Config{
InsecureSkipVerify: true,
})
if err != nil {
return err
}
}
if server.Auth != nil {
fmt.Println("Auth")
auth := smtp.PlainAuth("", server.Auth.Login, server.Auth.Password, server.Host)
err = c.Auth(auth)
if err != nil {
return err
}
}
if from == "" {
from = server.From
}
if from == "" {
return fmt.Errorf("From not set")
}
fmt.Printf("Set from: %s\n", from)
// Set the sender and recipient first
if err := c.Mail(from); err != nil {
return err
}
if len(to) == 0 {
to = []string{server.To}
}
if len(to) == 0 {
return fmt.Errorf("To not set")
}
for _, tt := range to {
if err := c.Rcpt(tt); err != nil {
return err
}
}
// Send the email body.
wc, err := c.Data()
if err != nil {
return err
}
fmt.Printf("Send data")
_, err = wc.Write(data)
if err != nil {
return err
}
err = wc.Close()
if err != nil {
return err
}
fmt.Println("Code connection")
// Send the QUIT command and close the connection.
err = c.Quit()
if err != nil {
return err
}
fmt.Println("Done")
return nil
}