Is it possible to send email from localhost?

Viewed 38

My goal is to create a SMTP server to send an email from noreply@myname.com containing OTP.

The problem is, I code on my personal computer. Therefore, no public address or domain, yet. I tried to send email to myname@gmail.com, but I can't find it on the spam, or the inbox folders.

What I've did:

  1. run the go-smtp server. $ go run cmd/server/main.go
  2. run the go-smtp client. $ go run cmd/client/main.go

The go-smtp server output

(base) jason@Jasons-Mac-mini server % go run main.go
2022/09/23 13:35:38 Starting server at :1025
2022/09/23 13:56:06 Mail from: test@localhost
2022/09/23 13:56:06 Rcpt to: // email redacted for stackoverflow
2022/09/23 13:56:06 Data: This is the email body

The go-smtp client output

(base) jason@Jasons-Mac-mini client % go run main.go
2022/09/23 13:56:06 Mail sent! time elapsed: 1.988625ms

cmd/client/main.go

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/emersion/go-smtp"
)

func main() {
    start := time.Now()

    // Connect to the remote SMTP server.
    c, err := smtp.Dial("localhost:1025")
    if err != nil {
        log.Fatal(err)
    }

    // Set the sender and recipient first
    if err := c.Mail("test@localhost", nil); err != nil {
        log.Fatal(err)
    }
    if err := c.Rcpt("jasonong713@gmail.com"); err != nil {
        log.Fatal(err)
    }

    // Send the email body.
    wc, err := c.Data()
    if err != nil {
        log.Fatal(err)
    }
    _, err = fmt.Fprintf(wc, "This is the email body")
    if err != nil {
        log.Fatal(err)
    }
    err = wc.Close()
    if err != nil {
        log.Fatal(err)
    }

    // Send the QUIT command and close the connection.
    err = c.Quit()
    if err != nil {
        log.Fatal(err)
    }

    log.Println("Mail sent! time elapsed:", time.Since(start))
}

cmd/server/main.go

package main

import (
    "log"
    "time"

    "github.com/emersion/go-smtp"
    "github.com/godataid/sendemail"
)

func main() {
    be := &sendemail.Backend{}

    s := smtp.NewServer(be)

    s.Addr = ":1025"
    s.Domain = "localhost"
    s.ReadTimeout = 10 * time.Second
    s.WriteTimeout = 10 * time.Second
    s.MaxMessageBytes = 1024 * 1024
    s.MaxRecipients = 50
    s.AllowInsecureAuth = true

    log.Println("Starting server at", s.Addr)
    if err := s.ListenAndServe(); err != nil {
        log.Fatalln(err)
    }
}

backend.go

package sendemail

import "github.com/emersion/go-smtp"

type Backend struct{}

// Authenticate a user. Return smtp.ErrAuthUnsupported if you don't want to
// support this.
func (be *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
    return nil, smtp.ErrAuthUnsupported
}

// Called if the client attempts to send mail without logging in first.
// Return smtp.ErrAuthRequired if you don't want to support this.
func (be *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
    return &Session{}, nil
}

session.go

package sendemail

import (
    "io"
    "log"

    "github.com/emersion/go-smtp"
)

type Session struct{}

// Discard currently processed message.
func (s *Session) Reset() {}

// Free all resources associated with session.
func (s *Session) Logout() error {
    return nil
}

// Set return path for currently processed message.
func (s *Session) Mail(from string, opts smtp.MailOptions) error {
    log.Println("Mail from:", from)
    return nil
}

// Add recipient for currently processed message.
func (s *Session) Rcpt(to string) error {
    log.Println("Rcpt to:", to)
    return nil
}

// Set currently processed message contents and send it.
func (s *Session) Data(r io.Reader) error {
    if b, err := io.ReadAll(r); err != nil {
        return err
    } else {
        log.Println("Data:", string(b))
    }
    return nil
}
0 Answers
Related