mirror of
https://github.com/GRFreire/nthmail.git
synced 2026-01-09 04:49:39 +00:00
this way, when the inbox route is called, there is no need to parse all mails neither request them from db just so it can have their subject
133 lines
2.4 KiB
Go
133 lines
2.4 KiB
Go
package mail_server
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/GRFreire/nthmail/pkg/mail_utils"
|
|
"github.com/emersion/go-smtp"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
type Backend struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func (backend *Backend) NewSession(c *smtp.Conn) (smtp.Session, error) {
|
|
tx, err := backend.db.Begin()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Session{
|
|
tx: tx,
|
|
}, nil
|
|
}
|
|
|
|
type Session struct {
|
|
tx *sql.Tx
|
|
from, rcpt string
|
|
arrived_at int64
|
|
}
|
|
|
|
func (session *Session) AuthPlain(username, password string) error {
|
|
return nil
|
|
}
|
|
|
|
func (session *Session) Mail(from string, opts *smtp.MailOptions) error {
|
|
session.arrived_at = time.Now().UTC().Unix()
|
|
|
|
session.from = from
|
|
return nil
|
|
}
|
|
|
|
func (session *Session) Rcpt(to string, opts *smtp.RcptOptions) error {
|
|
session.rcpt = to
|
|
|
|
return nil
|
|
}
|
|
|
|
func (session *Session) Data(reader io.Reader) error {
|
|
defer session.tx.Rollback()
|
|
if bytes, err := io.ReadAll(reader); err != nil {
|
|
return err
|
|
} else {
|
|
|
|
stmt, err := session.tx.Prepare("INSERT INTO mails (arrived_at, rcpt_addr, from_addr, subject, data) VALUES (?, ?, ?, ?, ?)")
|
|
if err != nil {
|
|
println(err)
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
mail_obj, err := mail_utils.Parse_mail(bytes, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = stmt.Exec(session.arrived_at, session.rcpt, session.from, mail_obj.Subject, bytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = session.tx.Commit()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (session *Session) Reset() {}
|
|
|
|
func (session *Session) Logout() error {
|
|
return nil
|
|
}
|
|
|
|
func Start(db *sql.DB) error {
|
|
backend := &Backend{
|
|
db: db,
|
|
}
|
|
|
|
server := smtp.NewServer(backend)
|
|
|
|
domain, exists := os.LookupEnv("MAIL_SERVER_DOMAIN")
|
|
if !exists {
|
|
domain = "localhost"
|
|
}
|
|
|
|
var port int
|
|
var err error
|
|
port_str, exists := os.LookupEnv("MAIL_SERVER_PORT")
|
|
if exists {
|
|
port, err = strconv.Atoi(port_str)
|
|
if err != nil {
|
|
return errors.New("env:MAIL_SERVER_PORT is not a number")
|
|
}
|
|
} else {
|
|
port = 1025
|
|
}
|
|
|
|
server.Addr = fmt.Sprintf(":%d", port)
|
|
server.Domain = domain
|
|
server.WriteTimeout = 60 * time.Second
|
|
server.ReadTimeout = 60 * time.Second
|
|
server.MaxMessageBytes = 1024 * 1024
|
|
server.MaxRecipients = 50
|
|
server.AllowInsecureAuth = true
|
|
|
|
log.Println("Starting mail server at", server.Addr)
|
|
if err := server.ListenAndServe(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|