Skip to content

Instantly share code, notes, and snippets.

@andelf
Created March 8, 2013 18:40
Show Gist options
  • Select an option

  • Save andelf/5118732 to your computer and use it in GitHub Desktop.

Select an option

Save andelf/5118732 to your computer and use it in GitHub Desktop.
golang net/smtp SMTP AUTH LOGIN Auth Handler
// MIT license (c) andelf 2013
import (
"net/smtp"
"errors"
)
type loginAuth struct {
username, password string
}
func LoginAuth(username, password string) smtp.Auth {
return &loginAuth{username, password}
}
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", []byte{}, nil
}
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
switch string(fromServer) {
case "Username:":
return []byte(a.username), nil
case "Password:":
return []byte(a.password), nil
default:
return nil, errors.New("Unkown fromServer")
}
}
return nil, nil
}
// usage:
// auth := LoginAuth("loginname", "password")
// err := smtp.SendMail(smtpServer + ":25", auth, fromAddress, toAddresses, []byte(message))
// or
// client, err := smtp.Dial(smtpServer)
// client.Auth(LoginAuth("loginname", "password"))
@tmack8080

Copy link
Copy Markdown

This worked for me using:
Server: smtp-mail.outlook.com
Port: 587
SMTP security: STARTTLS

Thank you for posting.

@andboson

Copy link
Copy Markdown

thx dude!

@MaoJianwei

Copy link
Copy Markdown

this works! many thanks!

@FeranyDev

Copy link
Copy Markdown

Oh, it's so beautiful.

@AzraelJi

Copy link
Copy Markdown

666

@three-ball

Copy link
Copy Markdown

Very useful, Thanks for your code, this works for me!

@karlovskiy

Copy link
Copy Markdown

Also, there is login auth support in go-mail package https://github.com/go-gomail/gomail/blob/master/auth.go

@hamdismaoui

Copy link
Copy Markdown

Thank you so much!
Solution still working fine.

@jypelle

jypelle commented Jan 10, 2024

Copy link
Copy Markdown

And if you don't want to choose between PLAIN and LOGIN:

func PlainOrLoginAuth(username, password, host string) smtp.Auth {
	return &plainOrLoginAuth{username: username, password: password, host: host}
}

func isLocalhost(name string) bool {
	return name == "localhost" || name == "127.0.0.1" || name == "::1"
}

type plainOrLoginAuth struct {
	username   string
	password   string
	host       string
	authMethod string
}

func (a *plainOrLoginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
	// Must have TLS, or else localhost server.
	// Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
	// In particular, it doesn't matter if the server advertises PLAIN auth.
	// That might just be the attacker saying
	// "it's ok, you can trust me with your password."
	if !server.TLS && !isLocalhost(server.Name) {
		return "", nil, errors.New("unencrypted connection")
	}
	if server.Name != a.host {
		return "", nil, errors.New("wrong host name")
	}
	if !slices.Contains(server.Auth, "PLAIN") {
		a.authMethod = "LOGIN"
		return a.authMethod, nil, nil
	} else {
		a.authMethod = "PLAIN"
		resp := []byte("\x00" + a.username + "\x00" + a.password)
		return a.authMethod, resp, nil
	}
}

func (a *plainOrLoginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
	if !more {
		return nil, nil
	}

	if a.authMethod == "PLAIN" {
		// We've already sent everything.
		return nil, errors.New("unexpected server challenge")
	}

	switch {
	case bytes.Equal(fromServer, []byte("Username:")):
		return []byte(a.username), nil
	case bytes.Equal(fromServer, []byte("Password:")):
		return []byte(a.password), nil
	default:
		return nil, fmt.Errorf("unexpected server challenge: %s", fromServer)
	}
}

@jrichardsz

Copy link
Copy Markdown

Thanks a lot!!!

@nicmwe

nicmwe commented May 15, 2024

Copy link
Copy Markdown

Thank you for this!

@AmrMady

AmrMady commented Dec 3, 2024

Copy link
Copy Markdown

Thank you

@ablogo

ablogo commented Aug 3, 2026

Copy link
Copy Markdown

Microsoft has permanently disabled Basic Authentication in Exchange Online (Microsoft 365), you will receive the next message "Authentication unsuccessful, basic authentication is disabled".

Unfortunately this code no longer work, it's mandatory implement OAuth 2.0 or another method accepted by Microsoft

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment