FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour tGmail class
Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
tGmail class
Posted: Wed May 28, 2025 12:29 AM

I do not use gmail nor do I recommend it to my clients. However, some insist on using it. All was find until the new "security" changes, and I know that is why the tGmail class was created.

I setup a gmail account, and I got the ID and secret ID. I plugged the testgmail code into my existing application for testing. Connecting to Google is annoying, but I got past all of that. Then I tried sending an email to one of my accounts ( modifying the sample code ) and got the following:

    msgStop( "Failed to send email. You may not have authorized the required permissions..." )

What are some of the things I should be checking. I'm building with Visual Studio, community, latest edition and the build has no errors.

Ultimately what I need to do is pretty simple. However as I see the Google instructions for the API it seems to make it more difficult. Here is what I want to accomplish:

1) My client ( and application ) creates an email.

2) I want to have them click on the button and send the email.

3) I want the client to have their own user ID and secret passwords. It appears they have to use my developer ID and secret id with their account.

4) Do they really need to start a connection every time, or can we bypass this to occur automatically ?

I've searched the forum but it appears, at least in the English forum, this is not recently discussed.

Thanks.

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 284
Joined: Mon Oct 24, 2005 08:04 PM
Re: tGmail class
Posted: Wed May 28, 2025 04:11 AM

Tim,

I'm in the same position as you. I've registered my app on the google cloud console and I'm going through the process of verification. There are quite a few hoops to jump through. I'm getting the same message as you and I don't know if this is because I haven't completed the verification process or if there is some other problem.

On the google cloud console under the Audience page do you have your Publishing Status as In Production or Testing? Mine is set to "In production" and I don't want to set it to "Back to testing" or I'll have to start through the whole verification process from the beginning. I'd be curious to know what setting you are using here.

Under the Data Access page what scopes have you asked for? I believe the gmail class is asking for ...

auth/userinfo.profile

auth/userinfo.email

auth/gmail.send

so you may need to have at least these 3 scopes selected

Office365 is a bigger issue for me as gmail still allows you to use SMTP and the "Less secure app" option to send emails via SMTP.

Office365 on the other hand is switching to oAuth and especially those users that are using Godday to host their website wherein GoDaddy acts as a middleman for Office365 and they have admin control, as opposed to the company/customer being a direct tenant. So, GoDaddy is forcing their users to oAuth if they are using Office365. This has been my experience. Anyone else using SMTP to send email through Office365?

Thanks,

Randal

Posts: 231
Joined: Fri Jul 20, 2012 01:49 AM
Re: tGmail class
Posted: Wed May 28, 2025 06:08 AM
Hey there.

Probably you are not checking the item to allow send email.
Please check this video showing how it works

https://youtu.be/bX0YFNlYowQ?si=xKoD1a-OPx_KgOb7

Any issue let me know
Regards,

Lailton Fernando Mariano
Posts: 284
Joined: Mon Oct 24, 2005 08:04 PM
Re: tGmail class
Posted: Wed May 28, 2025 11:47 AM

Lailton,

Thank you for your reply. I am checking the box to allow it to send email.

Thanks,

Randal

Posts: 284
Joined: Mon Oct 24, 2005 08:04 PM
Re: tGmail class
Posted: Wed May 28, 2025 02:07 PM
Lailton,

A little follow up.

I setup a test using Postman and I am able to send email using gmail oAuth this way, i.e. using the same client id, client secret, etc. I am using the scope https://mail.google.com/ with Postman. I modified gmail.prg to include this scope however, I still get the same error message that Tim mentioned.

What else could it be?

Thanks,
Randal
Lailton wrote: Hey there.

Probably you are not checking the item to allow send email.
Please check this video showing how it works

https://youtu.be/bX0YFNlYowQ?si=xKoD1a-OPx_KgOb7

Any issue let me know
Posts: 284
Joined: Mon Oct 24, 2005 08:04 PM
Re: tGmail class
Posted: Wed May 28, 2025 02:31 PM

I don't know if this helps however, I uncommented line number 268 in gmail.prg and saved the value being returned:

msgStop( hb_jsonEncode( hBuffer ) )

{"error":{"code":400,"message":"Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJmb29fYmFyX2JheiINCk1JTUUtVmVyc2lvbjogMS4wDQpGcm9tOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClJlcGx5LVRvOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClRvOiByZmVyZ3Vzb25AcmRmc29mdHdhcmUuY29tDQpTdWJqZWN0OiBpdCBpcyBhIHRlc3QNCg0KLS1mb29fYmFyX2Jheg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9InV0Zi04Ig0KTUlNRS1\r\nWZXJzaW9uOiAxLjANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGI+TWVzc2FnZSBmcm9tIEdtYWlsIG9BdXRoMjwvYj4NCg0K\r\n\"","errors":[{"message":"Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJmb29fYmFyX2JheiINCk1JTUUtVmVyc2lvbjogMS4wDQpGcm9tOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClJlcGx5LVRvOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClRvOiByZmVyZ3Vzb25AcmRmc29mdHdhcmUuY29tDQpTdWJqZWN0OiBpdCBpcyBhIHRlc3QNCg0KLS1mb29fYmFyX2Jheg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9InV0Zi04Ig0KTUlNRS1\r\nWZXJzaW9uOiAxLjANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGI+TWVzc2FnZSBmcm9tIEdtYWlsIG9BdXRoMjwvYj4NCg0K\r\n\"","reason":"invalid"}],"status":"INVALID_ARGUMENT","details":[{"@type":"type.googleapis.com/google.rpc.BadRequest","fieldViolations":[{"field":"message.raw","description":"Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJmb29fYmFyX2JheiINCk1JTUUtVmVyc2lvbjogMS4wDQpGcm9tOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClJlcGx5LVRvOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClRvOiByZmVyZ3Vzb25AcmRmc29mdHdhcmUuY29tDQpTdWJqZWN0OiBpdCBpcyBhIHRlc3QNCg0KLS1mb29fYmFyX2Jheg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9InV0Zi04Ig0KTUlNRS1\r\nWZXJzaW9uOiAxLjANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGI+TWVzc2FnZSBmcm9tIEdtYWlsIG9BdXRoMjwvYj4NCg0K\r\n\""}]}]}}

Thanks,

Randal

Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
Re: tGmail class
Posted: Wed May 28, 2025 09:46 PM

Lailton,

Actually, I did watch the video, and yes, I do check the box.

I did not have gmail so I set up an account. I then created a project and got my iD's. I plugged them into the sample and it showed all the steps. However it did not send the gmail from my account.

I then went back into Google to look at the info again. Although it was allowing me to go in and complete all the steps, when I looked for my previous authorization ( or maybe it's a project ), it was nowhere to be found. Now that is really strange, but considering Google, I wasn't surprised.

I never did find it ... So at that point I was frustrated.

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 231
Joined: Fri Jul 20, 2012 01:49 AM
Re: tGmail class
Posted: Thu May 29, 2025 12:56 AM
Randal,

Try edit the gmail.prg
line 257
cBuffer := ::mimeMultipart( cHeader, cMessage, lHTML, aAttachment )
hPost := { "raw" => strtran( hb_base64encode( cBuffer, len( cBuffer ) ), "\r\n", "" ) }
Can you add this strtran and check if it works?

Are you using Harbour or xHarbour?
Thanks
Regards,

Lailton Fernando Mariano
Posts: 284
Joined: Mon Oct 24, 2005 08:04 PM
Re: tGmail class
Posted: Thu May 29, 2025 02:43 PM
Lailton,

Thank you for your reply.

I did edit line 257 with your change but still have the same problem.

{"error":{"code":400,"message":"Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJmb29fYmFyX2JheiINCk1JTUUtVmVyc2lvbjogMS4wDQpGcm9tOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClJlcGx5LVRvOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClRvOiByZmVyZ3Vzb25AcmRmc29mdHdhcmUuY29tDQpTdWJqZWN0OiBpdCBpcyBhIHRlc3QNCg0KLS1mb29fYmFyX2Jheg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9InV0Zi04Ig0KTUlNRS1\r\nWZXJzaW9uOiAxLjANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGI+TWVzc2FnZSBmcm9tIEdtYWlsIG9BdXRoMjwvYj4NCg0K\r\n\"","errors":[{"message":"Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJmb29fYmFyX2JheiINCk1JTUUtVmVyc2lvbjogMS4wDQpGcm9tOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClJlcGx5LVRvOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClRvOiByZmVyZ3Vzb25AcmRmc29mdHdhcmUuY29tDQpTdWJqZWN0OiBpdCBpcyBhIHRlc3QNCg0KLS1mb29fYmFyX2Jheg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9InV0Zi04Ig0KTUlNRS1\r\nWZXJzaW9uOiAxLjANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGI+TWVzc2FnZSBmcm9tIEdtYWlsIG9BdXRoMjwvYj4NCg0K\r\n\"","reason":"invalid"}],"status":"INVALID_ARGUMENT","details":[{"@type":"type.googleapis.com/google.rpc.BadRequest","fieldViolations":[{"field":"message.raw","description":"Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJmb29fYmFyX2JheiINCk1JTUUtVmVyc2lvbjogMS4wDQpGcm9tOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClJlcGx5LVRvOiByZGZzb2Z0d2FyZUBnbWFpbC5jb20NClRvOiByZmVyZ3Vzb25AcmRmc29mdHdhcmUuY29tDQpTdWJqZWN0OiBpdCBpcyBhIHRlc3QNCg0KLS1mb29fYmFyX2Jheg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9InV0Zi04Ig0KTUlNRS1\r\nWZXJzaW9uOiAxLjANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGI+TWVzc2FnZSBmcm9tIEdtYWlsIG9BdXRoMjwvYj4NCg0K\r\n\""}]}]}}

I am using Harbour/Borland for this test.

Thanks,
Randal
Lailton wrote: Randal,

Try edit the gmail.prg
line 257
cBuffer := ::mimeMultipart( cHeader, cMessage, lHTML, aAttachment )
hPost := { "raw" => strtran( hb_base64encode( cBuffer, len( cBuffer ) ), "\r\n", "" ) }
Can you add this strtran and check if it works?

Are you using Harbour or xHarbour?
Thanks
Posts: 231
Joined: Fri Jul 20, 2012 01:49 AM
Re: tGmail class
Posted: Thu May 29, 2025 07:54 PM

Hum, very weird,

I am out this week, I should return Sunday to my house, then I will take some time and review it.

so far it works fine here, but I will double check and do a test with harbour+borland.

I will let you know the result.

Regards,

Lailton Fernando Mariano
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: tGmail class
Posted: Fri May 30, 2025 02:14 AM
Hi,

ChatGPT explains the error as follows:

The Gmail API expects the message.raw field to contain a valid Base64-encoded string representing a complete MIME-formatted email.

The provided string was not valid Base64 and could not be decoded. This usually happens when:

The Base64 string contains line breaks (\r\n). Gmail requires a single-line Base64 string.

Padding characters (=) are not removed, if you're using Base64URL.

You're using standard Base64, but Gmail expects Base64URL (+ โ†’ -, / โ†’ _).

To fix this, ensure that:

The MIME content is correct and complete.

The string is encoded to Base64 without any line breaks.

The final string is Base64URL-safe and has no padding characters.

Best regards,
Otto

Some time ago I created a PowerShell-based workflow.
In the attached PDF, you can see how PowerShell handles the entire Gmail OAuth2 process automatically โ€” including token handling, Base64URL encoding, and MIME message creation.

It might help you compare with your Harbour implementation and spot the differences.

https://winhotel-sandbox.com/docs/gmailmitpowershell.pdf


Clear explanation of the error in English:

โŒ Error (simplified and explained):

"error": {
"code": 400,
"message": "Invalid value at 'message.raw' (TYPE_BYTES), Base64 decoding failed for \"Q29u...\""
}
🧠 What does this actually mean?
The Gmail API expects the message.raw field to contain a valid Base64-encoded string representing a complete MIME-formatted email.

But the provided string is invalid:

Base64 error: Gmail tried to decode the string and failed.

TYPE_BYTES means the field must contain raw binary data, encoded as Base64 โ€“ but it wasnโ€™t valid.

Root cause reported by Google:
"Base64 decoding failed"

🔍 Common causes of this error:
1. โŒ The Base64 string contains line breaks (\r\n)
โ†’ Gmail expects a single-line Base64 string without any line breaks.
โ†’ Example: hb_base64encode() may insert \r\n every 76 characters. You must remove them.

2. โŒ Padding characters (=) were not removed (for Base64URL)
โ†’ If you're using Base64URL, the = padding must be removed.

3. โŒ You're using standard Base64, but Gmail expects Base64URL
โ†’ You must replace:

+ with -

/ with _

โœ… Correct way to encode in Harbour:

cMime := ::mimeMultipart( ... ) // your MIME content
cRaw := hb_base64encode( cMime, Len(cMime) )

// Gmail requires: no line breaks, Base64URL-safe
cRaw := strtran( cRaw, CRLF, "" )
cRaw := strtran( cRaw, LF, "" )
cRaw := strtran( cRaw, "+", "-" )
cRaw := strtran( cRaw, "/", "_" )
cRaw := strtran( cRaw, "=", "" ) // Remove padding

hPost := { "raw" => cRaw }
🧾 In plain language:
"You tried to send an email, but the message.raw content was not properly encoded. The Gmail API couldn't parse it because the Base64 string was malformed."

📌 Steps to fix:
Make sure your MIME content is valid

Encode the whole message as one continuous Base64 string

Convert it to Base64URL format

Ensure:

No \r\n

No =

No / or + in the final string
Posts: 231
Joined: Fri Jul 20, 2012 01:49 AM
Re: tGmail class
Posted: Fri May 30, 2025 07:15 PM

Correct Otto.

hb_base64encode is supost to automatic convert it. \r\n is the break line but normally it is encoded too.

I have no this issue with last version harbour + msvc ( 32/64 ) but I will double check when return to my house

with bcc.

Regards,

Lailton Fernando Mariano
Posts: 114
Joined: Fri Jul 21, 2006 07:15 PM
Re: tGmail class
Posted: Fri Jun 06, 2025 12:16 PM

Hi guys.

I recently had the same problem with a client, I tried all the options mentioned above by Mr. Tim, I spent a few nights trying to understand the process, with the client pressuring me every hour. Finally, I gave up on implementing in Harbour/xHarbour and tried to create an external solution in Dot Net through Visual Studio. I created a test solution with the same data that I used in xHarbour/Harbour and it worked in Dot Net. I decided to create a call in my program to this other one in Dot Net. Basically my system does: WaitRun( cFolder+'ConsoleApp ' + cFrom+' ' + cTo + ' ' + '"'+cSubject+'"' + ' ' + '"'+cBody+'"' + cFiles, 0 ), where 'ConsoleApp' is the executable in Dot Net that gets the Gmail credentials in a 'credentials.json' file. This client of mine sends on average about 100 emails per day and I never bothered with it again. If anyone is interested in a solution like this and needs help or more details, they can contact me. I intend to develop the same metod to Office365.

Regards.

FWH / xHarbour / BCC / MySql

Visual Studio / Harbour / DotNet Maui / C#
Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
Re: tGmail class
Posted: Fri Jun 06, 2025 11:50 PM

I would be interested in that though my preference is to find a solution that works within my .exe without having to upload a separate program to my clients for them to call.

Laiton, I am curious - what type of GMAIL account do you have. I setup the free personal account. I am building with FWH, Harbour 64, and and the latest Microsoft Visual Studio Community. Still I cannot get it to work with an authorization error. Perhaps it must be a paid gmail account ?

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 231
Joined: Fri Jul 20, 2012 01:49 AM
Re: tGmail class
Posted: Sat Jun 07, 2025 02:28 AM

I sent you by email a new version, please try it and let me know if does it works.

Regards,

Lailton Fernando Mariano