Deconfusing How To Use Gmail's SMTP server in 2024
I'm old enough to remember when writing an app to send emails from a Gmail account was cool. You click a couple things in your Google account console, you provide your username and password to your app, and zing, you're in business.
Now, in 2024, this process is not as simple as it used to be—which means that it's definitely not as cool.
Today I'm gonna show you exactly how you can make apps that send emails from your Gmail account, while avoiding some of the gotchas waiting for you during this process—most of which stem from Google's confusing, poorly documented, security console.
The app code
For simplicity, we're gonna use the following go
snippet, borrowed from a wonderful blog source, and use it as our sample application code.
package main
import (
"fmt"
"net/smtp"
"flag"
)
var username = flag.String("username", "", "gmail email address")
var password = flag.String("password", "", "gmail password")
var to = flag.String("to", "", "address receiving email")
func main() {
flag.Parse()
if *username == "" {
panic("no username")
}
if *password == "" {
panic("no password")
}
if *to == "" {
panic("no to address")
}
// Receiver email addresses.
rcvs := []string{
*to,
}
// smtp server configuration.
smtpHost := "smtp.gmail.com"
smtpPort := "587"
// Message.
message := []byte("This is a test email message.")
// Authentication.
auth := smtp.PlainAuth("", *username, *password, smtpHost)
// Sending email.
err := smtp.SendMail(smtpHost+":"+smtpPort, auth, *username, rcvs, message)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Email Sent Successfully!")
}
This code is extremely simple. When we run it, it should send an email with the message "This is a test email message." to the --to
address we provide.
Sending emails from your personal Gmail account
If you want to send emails from your personal Google account, your first step should be signing into your google account where you'll need to create an "App Password". This password will be used by the app code to send emails from your Gmail account.
Unfortunately, there's no way (that I've found) to be able to click your way to the "App Passwords" page using the console for a personal Gmail account.
For Google Workspaces or teams, you can find app passwords by clicking "Security" in the left side navigation bar, then clicking "2-step Verification" in the center of the page. "App Passwords" is usually found here. (You will probably need to set up 2-step verification on your Google account before continuing on, by the way).
But, for personal Google accounts, at least for me, "App Passwords" is not here.
Instead, you need to search for "App Passwords" in the console search bar in order to find it, like so.
Once you find the "App Passwords" page, you need to generate a new app password.
Let's create an app password called my-app
.
After we collect our newly generated app password that we should be able to supply as the password to our app, and successfully send an email.
ubuntu@ip-10-2-0-238:~/email_app$ ./email_app --username dustin@gmail.com --password "nkzh pnky qppz jtjw" --to dustin@dolthub.com
535 5.7.8 Username and Password not accepted. For more information, go to
5.7.8 https://support.google.com/mail/?p=BadCredentials gq13-20020a17090b104d00b002ad059491f6sm1779187pjb.5 - gsmtp
And we get denied.
Luckily, Gmail provides a url for us in the error message that... won't help us at all. It's actually full of irrelevant links for plebs.
Instead, the way to fix this is to simply generate a new app password, and try that one. We'll call this new one my-app-2
.
And of course the new password works as expected.
ubuntu@ip-10-2-0-238:~/email_app$ ./email_app --username dustin@gmail.com --password "pujx hhsi sdsu ewfz" --to dustin@dolthub.com
Email Sent Successfully!
Why does the second password work and not the first? Why? Because fuck you, that's why.
Now you might be thinking that the reason the first app password we generated didn't work was because we needed to use the Google console to verify that it was us who created the app password in the first (even though we didn't need to verify anything to get the second app password to work). Maybe this is just some additional security measure implemented by Google.
So, if we go back to the "Security" page, we can see the app passwords we created in our "Recent security activity".
And, if we click our app password my-app
that doesn't work, we can see Google wants us to verify that we in fact made the password.
So, after clicking "Yes, it was me", I tried our first app password again.
ubuntu@ip-10-2-0-238:~/email_app$ ./email_app --username dustin@gmail.com --password "nkzh pnky qppz jtjw" --to dustin@dolthub.com
535 5.7.8 Username and Password not accepted. For more information, go to
5.7.8 https://support.google.com/mail/?p=BadCredentials n7-20020a170902e54700b001eb3dadacffsm1853286plf.219 - gsmtp
And, once again, we're denied.
So the lesson here, I guess, is to always generate an additional app password in order get your apps to send emails from your personal Gmail account, cause something on Google's side is kinda fucky.
Sending emails from your Gmail team account/Google Workspaces
Now let's see if we can get our app working for a Google Workspaces account, which you might use for your entire team, like we do here at DoltHub.com for our dolthub.com
email addresses.
We're going to follow the same process we used above.
First, we sign-in to our Gmail team account, navigate to our account page, and click the "Security" section in the left navigation section.
Now, if we click "2-step Verification" (that you should set up before continuing on), and scroll down, we see "App Passwords" this time.
Like before, we create a new app password called my-app
, copy the generated password, and supply it to our email app.
ubuntu@ip-10-2-0-238:~/email_app$ ./email_app --username dustin@dolthub.com --password "vzuo vgth vqsq kebz" --to dustin@gmail.com
Email Sent Successfully!
And... it appears it works the first time? So... that's good, I suppose.
I also tried generating an additional app password and using that one. It also worked. Maybe team Google accounts get preferential app passwords or something that the free-loading, personal-account-having-ass-gmailers, like me, can't get.
My teammates weren't so lucky. The reason I'm writing this blog is because yesterday, two people on the team could not get their App Passwords using a dolthub.com email address to work testing DoltLab, our self-deployed collaboration platform. It was strange because the App Password would work from a simple script but not from the website backend.
The lesson here I guess is App Password is unreliable so keep trying until one works. This seems like a poor solution from Gmail at this point. I hope this blog catches the attention of the team in charge of this at Google HQ and something gets fixed.
Conclusion
In conclusion, I thought about one more reason why this sometimes works and sometimes doesn't. I thought maybe some asynchronous process on the Gmail SMTP server side just needed a bit more time to accept/validate the original app password I created for my personal Gmail account. Maybe I just didn't wait long enough for this process to complete before I tried to using the password.
So, after waiting about 30 minutes, I tried using it again.
ubuntu@ip-10-2-0-238:~/email_app$ ./email_app --username dustin@gmail.com --password "nkzh pnky qppz jtjw" --to dustin@dolthub.com
535 5.7.8 Username and Password not accepted. For more information, go to
5.7.8 https://support.google.com/mail/?p=BadCredentials jo3-20020a170903054300b001e904b1d164sm1897770plb.177 - gsmtp
Ugh.
Anyway, I hope this blog saves you from having to debug things that are really just the Gmail SMTP server misbehaving. If you know more information about what's going on with Gmail, or know of a better way to do the above, swing by our Discord.
Thanks for reading and don't forget to check out each of our cool products below:
- Dolt—it's Git for data.
- DoltHub—it's GitHub for data.
- DoltLab—it's GitLab for data.
- Hosted Dolt—it's RDS for Dolt databases.