Implementing OAuth 2.0 authentication for Gmail SMTP with Indy components

I have a working Delphi application that sends emails through Gmail’s SMTP servers using Indy components. The current implementation works fine but requires users to enable “Allow less secure apps” in their Google account settings.

I want to upgrade this solution to use OAuth 2.0 authentication instead of basic username/password authentication. This would eliminate the need for users to lower their security settings and comply with Google’s recommended security practices.

Here’s my current working code that uses basic authentication:

function TMainForm.SendMailMessage(SenderEmail, RecipientEmail, EmailSubject,
EmailContent, SMTPServer: String; SMTPPort: Integer; LoginName, LoginPass: String): Boolean;
begin
  Result := False;
  
  try
    MailMessage := nil;
    SSLHandler := nil;
    SMTPClient := nil;
    
    try
      // Configure email message
      try
        MailMessage := TIdMessage.Create(nil);
        MailMessage.From.Address := SenderEmail;
        MailMessage.Recipients.EMailAddresses := RecipientEmail;
        MailMessage.Subject := EmailSubject;
        MailMessage.Body.Text := EmailContent;
      except
        Exception.RaiseOuterException(Exception.Create('Failed to configure email message'));
      end;

      // Setup SSL/TLS handler
      try
        SSLHandler := TIdSSLIOHandlersocketopenSSL.Create(nil);
        SSLHandler.SSLOptions.Method := sslvTLSv1;
        SSLHandler.SSLOptions.Mode := sslmUnassigned;
        SSLHandler.SSLOptions.VerifyMode := [];
        SSLHandler.SSLOptions.VerifyDepth := 0;
      except
        Exception.RaiseOuterException(Exception.Create('SSL configuration failed'));
      end;

      // Configure SMTP client
      try
        SMTPClient := TIdSMTP.Create(nil);
        SMTPClient.IOHandler := SSLHandler;
        SMTPClient.UseTLS := utUseExplicitTLS;
        SMTPClient.Host := SMTPServer;
        SMTPClient.Port := SMTPPort;
        SMTPClient.Username := LoginName;
        SMTPClient.Password := LoginPass;
      except
        Exception.RaiseOuterException(Exception.Create('SMTP setup failed'));
      end;

      try
        SMTPClient.Connect;
        try
          SMTPClient.Send(MailMessage);
        finally
          SMTPClient.Disconnect;
        end;
      except
        Exception.RaiseOuterException(Exception.Create('Email transmission failed'));
      end;
      
    finally
      SMTPClient.Free;
      SSLHandler.Free;
      MailMessage.Free;
      Result := True;
    end;
    
  except
    on E: Exception do
    begin
      if E.InnerException <> nil then
        ShowMessage('Error: ' + E.Message + #13#13 + E.InnerException.Message)
      else
        ShowMessage('Error: ' + E.Message);
    end;
  end;
end;

What modifications do I need to make to integrate OAuth 2.0 authentication with this Indy SMTP implementation?

From my experience migrating legacy SMTP implementations, the biggest challenge isn’t just switching to OAuth2 but managing the entire token lifecycle properly. You’ll need to implement a web server or use the device flow to handle the initial authorization since Google requires user consent through their interface. Once you have the refresh token, store it securely and implement automatic token renewal before expiration. For the Indy side, I recommend using TIdSASLOAuth class but be aware that some older Indy versions have issues with the OAuth2 implementation. You might need to manually construct the SASL XOAUTH2 string and handle the authentication yourself. Also consider wrapping the entire authentication process in a retry mechanism since network issues during token refresh can cause intermittent failures that are hard to debug.

oauth with indy is bit tricky since you need to handle the token refresh manually. i’d suggest using TIdSASLOAuth class - set SMTPClient.SASLMechanisms to include oauth mechanism and pass your access token. dont forget to implement token refresh logic tho, tokens expire every hour usually.

The OAuth implementation requires several components beyond what you currently have. You’ll need to register your application with Google Cloud Console to obtain client credentials, then implement the authorization flow to get access tokens. For the SMTP part, replace the basic authentication with SASL XOAUTH2 mechanism - create a TIdSASLOAuth2 instance and assign it to your SMTPClient.SASLMechanisms. The tricky part is constructing the OAuth string properly, it needs to be base64 encoded in format “user=username\x01auth=Bearer token\x01\x01”. I found that handling token expiration gracefully is crucial since Gmail tokens typically last 3600 seconds. Consider implementing a token storage mechanism and refresh logic before each send operation to avoid authentication failures mid-process.