How to send a mail with using auth? - email

I'm using smtp package of golang to send the mail from localhost to the given mail address. But there is a problem I'm providing my email and password for it but it will show me the error of
535 5.7.8 Username and Password not accepted. Learn more at
5.7.8 https://support.google.com/mail/?p=BadCredentials p24sm107930499pfk.155 - gsmtp
they want that I have to allow less secure app to use my account But I don't want to allow that I tried a small piece of code for it.
Tried Example1:-
// Set up authentication information.
auth := smtp.PlainAuth(
"",
"email",
"password",
"smtp.gmail.com",
)
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
err := smtp.SendMail(
"smtp.gmail.com:25",
auth,
"emailFrom",
[]string{EmailToooo},
[]byte("This is the email body."),
)
if err != nil {
log.Fatal(err)
}
*Tried Example 2:- *
m := gomail.NewMessage()
m.SetHeader("From", "SenderEmail#gmail.com")
m.SetHeader("To", "Email_Tooo#gmail.com")
m.SetHeader("Subject", "Hello!")
m.SetBody("text/html", "Hello <b>Bob</b> and <i>Cora</i>!")
d := gomail.NewDialer("smtp.gmail.com", 587, "email", "password")
// Send the email to Bob, Cora and Dan.
if err := d.DialAndSend(m); err != nil {
fmt.Println(err)
}
I also tried a gopkg.in/gomail.v2 package for doing NoAuth mail but in this it will give me the error of port connection see in given code:-
m := gomail.NewMessage()
m.SetHeader("From", "from#example.com")
m.SetHeader("To", "to#example.com")
m.SetHeader("Subject", "Hello!")
m.SetBody("text/plain", "Hello!")
d := gomail.Dialer{Host: "localhost", Port: 587}
if err := d.DialAndSend(m); err != nil {
panic(err)
}
I also change the port to 8080 after doing 8080 it will not give any response it was showing only requesting.
Can anyone tell me that how will I send mail from localhost to the given mail address without auth?

Try to use port 587 on first example. It should be working.
err := smtp.SendMail(
"smtp.gmail.com:587",
auth,
"emailFrom",
[]string{EmailToooo},
[]byte("This is the email body."),
)
If you use smtp.gmail.com then the correct port is either 587 (TLS) or 465 (SSL), with the less secure app must be allowed.
Further information: https://support.google.com/a/answer/176600?hl=en

Related

how to load toml settings (GOLANG)

I'm trying to use toml to store the connection settings of a database.
I want to load these settings that are in a config.toml file and thus do my operations
I tried the following:
go code:
func Init() *sql.DB {
config, err := toml.LoadFile("config.toml")
if err != nil {
log.Fatal("Erro ao carregar variaveis de ambiente")
}
host := config.Get("postgres.host").(string)
port := config.Get("postgres.port").(string)
user := config.Get("postgres.user").(string)
password := config.Get("postgres.password").(string)
dbname := config.Get("postgres.dbname").(string)
stringConnection := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s", host, port, user, password, dbname)
db, err := sql.Open("postgres", stringConnection)
if err != nil {
panic(err)
}
fmt.Println("Sucesso ao realizar conexão com o banco de dados")
err = db.Ping()
return db
}
config.toml:
[postgres]
host = "localhost"
port = 5432
user = "postgres"
password = "ivaneteJC"
dbname = "webhook"
this attempt is returning an error, which unfortunately I do not know how to proceed
error:
panic: interface conversion: interface {} is int64, not string
Any solution ?
As for your error, like #tkausl said, you define port as integer, and not a string, yet you do type assertion of the value to string in this line
port := config.Get("postgres.port").(string)
Change the string to int64 like the error said and you should be fine.
Are you using the https://github.com/pelletier/go-toml package? If so, this package seems to also support unmarshalling config files into Go struct directly. This is a more convenient approach instead of having to config.Get each config one by one.
type PostgreConfig struct {
Host string
Port int
User string
Password string
Dbname string
}
type MyConfig struct {
Postgres *PostgreConfig
}
// Read the toml file content
doc, err := os.ReadFile("config.toml")
if err != nil {
panic(err)
}
// Parse the content
var cfg MyConfig
err = toml.Unmarshal(doc, &cfg)
if err != nil {
panic(err)
}
fmt.Println(cfg.Postgres.Host)
fmt.Println(cfg.Postgres.Port)
The solution with minimal changes:
// solution 1
port := config.Get("postgres.port")
stringConnection := fmt.Sprintf("host=%s port=%v user=%s password=%s dbname=%s", host, port, user, password, dbname)
// solution 2
port := config.Get("postgres.port").(int64)
stringConnection := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s", host, port, user, password, dbname)
// solution 3
// config.toml
port = "5432"

golang client fails to connect to mongo db server - sslv3 alert bad certificate

I'm trying to connect a go client to mongodb server running with ssl enabled. I get a clear error message indicating that the hand shake failed due to ssl error. I use a self signed certificate on the client side.
Got below from the mongodb server:
2017-05-13T04:38:53.910+0000 I NETWORK [thread1] connection accepted from 172.17.0.1:51944 #10 (1 connection now open)
2017-05-13T04:38:53.911+0000 E NETWORK [conn10] SSL: error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate
2017-05-13T04:38:53.911+0000 I - [conn10] end connection
Error from Go client:
Could not connect to mongodb_s1.dev:27017 x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "XYZ")
Tried multiple options, but didn't help
You can skip TLS security checks using InsecureSkipVerify = true. This allows you to use self-signed certificates. See the code from compose help below.
Instead of skipping security checks, it is advisable to add the CA used to sign your certificates to the list of trusted CAs of the system.
package main
import (
"crypto/tls"
"fmt"
"net"
"os"
"strings"
"gopkg.in/mgo.v2"
)
func main() {
uri := os.Getenv("MONGODB_URL")
if uri == "" {
fmt.Println("No connection string provided - set MONGODB_URL")
os.Exit(1)
}
uri = strings.TrimSuffix(uri, "?ssl=true")
Here:
tlsConfig := &tls.Config{}
tlsConfig.InsecureSkipVerify = true
dialInfo, err := mgo.ParseURL(uri)
if err != nil {
fmt.Println("Failed to parse URI: ", err)
os.Exit(1)
}
And here:
dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
return conn, err
}
session, err := mgo.DialWithInfo(dialInfo)
if err != nil {
fmt.Println("Failed to connect: ", err)
os.Exit(1)
}
defer session.Close()
dbnames, err := session.DB("").CollectionNames()
if err != nil {
fmt.Println("Couldn't query for collections names: ", err)
os.Exit(1)
}
fmt.Println(dbnames)
}

Go HTTP Request with Basic Auth returning a 401 instead of a 301 redirect

Using Go 1.5.1.
When I try to make a request to a site that automatically redirects to HTTPS using Basic Auth I would expect to get a 301 Redirect response, instead I get a 401.
package main
import "net/http"
import "log"
func main() {
url := "http://aerolith.org/files"
username := "cesar"
password := "password"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Println("error", err)
}
if username != "" || password != "" {
req.SetBasicAuth(username, password)
log.Println("[DEBUG] Set basic auth to", username, password)
}
cli := &http.Client{
}
resp, err := cli.Do(req)
if err != nil {
log.Println("Do error", err)
}
log.Println("[DEBUG] resp.Header", resp.Header)
log.Println("[DEBUG] req.Header", req.Header)
log.Println("[DEBUG] code", resp.StatusCode)
}
Note that curl returns a 301:
curl -vvv http://aerolith.org/files --user cesar:password
Any idea what could be going wrong?
A request to http://aerolith.org/files redirects to https://aerolith.org/files (note change from http to https). A request to https://aerolith.org/files redirects to https://aerolith.org/files/ (note addition of trailing /).
Curl does not follow redirects. Curl prints the 301 status for the redirect from http://aerolith.org/files to https://aerolith.org/files/.
The Go client follows the two redirects to https://aerolith.org/files/. The request to https://aerolith.org/files/ returns with status 401 because the Go client does not propagate the authorization header through the redirects.
Requests to https://aerolith.org/files/ from the Go client and Curl return status 200.
If you want to follow the redirects and auth successfully, set auth header in a CheckRedirect function:
cli := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return errors.New("stopped after 10 redirects")
}
req.SetBasicAuth(username, password)
return nil
}}
resp, err := cli.Do(req)
If you want to match what Curl does, use a transport directly. The transport does not follow redirects.
resp, err := http.DefaultTransport.RoundTrip(req)
The application can also use the client CheckRedirect function and a distinguished error to prevent redirects as shown in an answer to How Can I Make the Go HTTP Client NOT Follow Redirects Automatically?. This technique seems to be somewhat popular, but is more complicated than using the transport directly.
redirectAttemptedError := errors.New("redirect")
cli := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return redirectAttemptedError
}}
resp, err := cli.Do(req)
if urlError, ok := err.(*url.Error); ok && urlError.Err == redirectAttemptedError {
// ignore error from check redirect
err = nil
}
if err != nil {
log.Println("Do error", err)
}

Sending mail on localhost smtp does not work

I am trying to send an email to the localhost stmp server. I am using fakesmtp program to receive email from localhost.
Look at following code snippet
package mail
import (
"encoding/base64"
"fmt"
"log"
"net/mail"
"net/smtp"
"strings"
)
func encodeRFC2047(String string) string {
// use mail's rfc2047 to encode any string
addr := mail.Address{String, ""}
return strings.Trim(addr.String(), " <>")
}
func Send() {
// Set up authentication information.
smtpServer := "127.0.0.1:2525"
auth := smtp.PlainAuth(
"",
"admin",
"admin",
smtpServer,
)
from := mail.Address{"example", "info#example.com"}
to := mail.Address{"customer", "customer#example.com"}
title := "Mail"
body := "This is an email confirmation."
header := make(map[string]string)
header["From"] = from.String()
header["To"] = to.String()
header["Subject"] = encodeRFC2047(title)
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/plain; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
err := smtp.SendMail(
smtpServer,
auth,
from.Address,
[]string{to.Address},
[]byte(message),
//[]byte("This is the email body."),
)
if err != nil {
log.Fatal(err)
}
}
When I executed the send function, I've got the error unencrypted connection. Why?
Most likely the server does not allow you to use plain-text authentication over an unencrypted connection, which is a sensible default for almost any MTA out there. Either change authentication info to e.g. digest, or enable SSL/TLS in you client code.
Remember to use tcpdump or wireshark to check what is actually transmitted.

How to send an email using Go with an HTML formatted body?

This seems like a very common need, but I didn't find any good guides when I searched for it.
Assuming that you're using the net/smtp package and so the smtp.SendMail function, you just need to declare the MIME type in your message.
subject := "Subject: Test email from Go!\n"
mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
body := "<html><body><h1>Hello World!</h1></body></html>"
msg := []byte(subject + mime + body)
smtp.SendMail(server, auth, from, to, msg)
Hope this helps =)
I am the author of gomail. With this package you can easily send HTML emails:
package main
import (
"gopkg.in/gomail.v2"
)
func main() {
m := gomail.NewMessage()
m.SetHeader("From", "alex#example.com")
m.SetHeader("To", "bob#example.com")
m.SetHeader("Subject", "Hello!")
m.SetBody("text/html", "Hello <b>Bob</b>!")
// Send the email to Bob
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
if err := d.DialAndSend(m); err != nil {
panic(err)
}
}
You can also add a plain text version of the body in your email for the client that does not support HTML using the method AddAlternative.