OAuth2 Email: TOAuth, TGmail, TOutlookMail

Sources: source/classes/oauth.prg, source/classes/gmail.prg, source/classes/outlookmail.prg

FiveWin provides OAuth2 email support for Gmail (TGmail) and Outlook/Office 365 (TOutlookMail) through a common class hierarchy. TOAuth handles authentication, token management, and MIME message construction. TGmail implements the Gmail REST API, TOutlookMail uses Microsoft Graph. All network communication uses libcurl; the interactive login uses TWebView2.

OAuth2 Authentication Flow

sequenceDiagram participant App as "FWH App" participant WV as "TWebView2" participant Srv as "THttpServer" participant Cloud as "Provider API" App->>Srv: Start on local port App->>WV: Navigate to auth URL WV->>Cloud: User grants permission Cloud-->>WV: Redirect to localhost/?code=XYZ WV->>Srv: HTTP GET with auth code Srv-->>App: Return captured code App->>WV: Close browser window App->>Cloud: POST /token (code + client_secret) Cloud-->>App: JSON {access_token, refresh_token} Note over App: Store refresh_token locally App->>Cloud: Send email via REST API

TOAuth: Base Class

TOAuth provides the core OAuth2 workflow and MIME multipart construction. It manages client credentials, the local HTTP server for redirect capture, and token lifecycle including automatic refresh.

DATATypeDescription
cClientIdCharacterOAuth2 client ID from provider
cClientSecretCharacterOAuth2 client secret
cRedirectUriCharacterRedirect URI (defaults to http://localhost:2025)
cAccessTokenCharacterCurrent access token
cRefreshTokenCharacterPersistent refresh token
MethodDescription
GetAuthCode()Opens WebView2, navigates to provider auth URL, captures authorization code via local THttpServer
GetToken()Exchanges authorization code for access and refresh tokens via POST to /token endpoint
RefreshToken()Uses refresh_token to obtain a new access_token when the current one expires
mimeMultipart(cTo,cSubj,cBody,aAttach)Builds an RFC-compliant MIME multipart message with base64-encoded attachments
getFileMime(cPath)Returns MIME type string for a given file extension (lookup table for jpg, png, pdf, etc.)

TGmail: Google Gmail API

MethodDescription
New(cClientId,cClientSecret,cUser)Create a TGmail instance for the specified user. Triggers the OAuth2 auth flow if no token is cached.
Send(cTo,cSubj,cBody,aAttach)Send an email via the Gmail API endpoint. aAttach is an array of file paths.
GetToken()Obtain a fresh access token, checking validity via the tokeninfo endpoint first.
RefreshToken()Force refresh of the access token from the stored refresh token.

TGmail sends via https://gmail.googleapis.com/gmail/v1/users/me/messages/send?uploadType=multipart and requires a Google Cloud Console "Web Application" client ID with redirect URI set to http://localhost:2025.

TOutlookMail: Microsoft Graph API

MethodDescription
New(cClientId,cTenantId,cUser)Create a TOutlookMail instance. cTenantId identifies the Azure AD tenant.
Send(cTo,cSubj,cBody,aAttach)Send email via Microsoft Graph /users/{user}/sendMail endpoint. Supports HTML body and attachments.
me()Retrieve the authenticated user's profile from https://graph.microsoft.com/v1.0/me

Required OAuth2 scopes: Mail.Send, offline_access, openid, profile, SMTP.Send, User.Read. Microsoft may rotate refresh tokens; the class detects new refresh tokens in token responses and updates the local store automatically.

Example: Gmail OAuth2 Send

#include "FiveWin.ch"

function Main()

   local oGmail := TGmail():New( ;
      "your-client-id.apps.googleusercontent.com", ;
      "your-client-secret", ;
      "user@gmail.com" )

   // The OAuth2 browser window opens automatically
   // if no cached token is found

   if ! Empty( oGmail:cAccessToken )
      oGmail:Send( "recipient@example.com", ;
                   "Test from FWH", ;
                   "<h1>Hello!</h1><p>Sent via Gmail API.</p>", ;
                   { "C:\docs\invoice.pdf" } )
      MsgInfo( "Email sent successfully!" )
   else
      MsgStop( "Authentication failed" )
   endif

return nil

Notes

Ver También