I recently switched my Java application from using sendmail to Gmail API for sending emails through Google Workspace. Everything works fine except for one major issue with character encoding.
When I send HTML emails that contain special UTF-8 characters like curly quotes and fancy apostrophes, Gmail API seems to convert them all into question marks. The weird part is that these characters display correctly before I send the email, but once Gmail processes and delivers the message, all the special characters become literal “?” symbols.
For example, when I try to send text with stylized quotes like “Hello there” it gets converted to ?Hello there? in the final email that recipients see.
I’m setting the charset properly in my HTML:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
</html>
Here’s my Java code for sending through Gmail API:
MimeMessage msg = new MimeMessage(mailSession);
msg.setSubject(emailSubject);
msg.setContent(htmlContent, "text/html");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
msg.writeTo(outputStream);
byte[] emailBytes = outputStream.toByteArray();
String base64Email = Base64.encodeBase64URLSafeString(emailBytes);
Message gmailMessage = new Message();
gmailMessage.setRaw(base64Email);
gmailMessage = gmailService.users().messages().send(userEmail, gmailMessage).execute();
The issue appears in all email clients because the question marks are now part of the actual message content. Has anyone encountered this UTF-8 encoding problem with Gmail API before?
I ran into this exact problem six months ago when migrating from SMTP to Gmail API. The issue is that you need to set the encoding headers properly on the MimeMessage before converting to bytes. Add these lines after creating your MimeMessage:
msg.setHeader("Content-Type", "text/html; charset=UTF-8");
msg.setHeader("Content-Transfer-Encoding", "quoted-printable");
The key difference from the other solution is using quoted-printable encoding rather than relying on base64 handling. This preserves special characters during the Gmail API transmission process. Make sure your source HTML file is also saved as UTF-8 without BOM if you’re reading from files.
This encoding nightmare plagued me for weeks when I switched to Gmail API. The root cause is actually in how you’re creating the MimeMessage object itself. You need to ensure the mail session has proper encoding defaults set up front. Before creating your MimeMessage, configure the session properties like this:
Properties props = new Properties();
props.put("mail.mime.charset", "UTF-8");
props.put("mail.mime.encodefilename", "true");
Session mailSession = Session.getDefaultInstance(props);
Then when you create the message, the encoding will be handled correctly from the start. Also double-check that your htmlContent string variable is properly UTF-8 encoded when it reaches this code block. I discovered mine was getting corrupted during string manipulation operations earlier in the pipeline. The Gmail API itself handles UTF-8 fine once the MimeMessage is properly constructed with the right encoding foundation.
had similar issue last month. try setting the content-type explicitly when calling setContent - use msg.setContent(htmlContent, "text/html; charset=UTF-8") instead of just “text/html”. also make sure your string encoding is utf-8 before creating the mimemessage. fixed it for me when curly quotes were getting mangled.