We are trying to sign an email message with DKIM. The email is successfully sent to the recipient via Gmail's Api; however, it fails DKIM validation when we sign it with a domain that has a valid DKIM setup. The domain has a valid DKIM setup (https://mxtoolbox.com/SuperTool.aspx?action=dkim%3aunsub.eeunsub.com%3as1&run=toolpage) and the DKIM passes when we send emails using other email providers such as AWS SES (screenshot added, see below).
private static void SendEmail()
{
ClientSecrets clientSecrets = new ClientSecrets
{
ClientId = ClientId,
ClientSecret = ClientSecret
};
TokenResponse token = new TokenResponse
{
AccessToken = "",
RefreshToken = _espApiEndpoint.RefreshToken
};
IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = clientSecrets,
Scopes = new string[] { GmailService.Scope.GmailSend }
});
UserCredential credential = new UserCredential(flow, "me", token);
BaseClientService.Initializer intializer = new BaseClientService.Initializer
{
ApplicationName = "GmailEspApiClient",
HttpClientInitializer = credential
};
var gmail = new GmailService(intializer);
string message = @"From: Xxx <[email protected]>
Date: Thu, 14 Mar 2024 09:59:20 -0700
Subject: Gmail EE est
Message-Id: <[email protected]>
Reply-To: xxx <[email protected]>
To: Dan <[email protected]>
X-EE-RunId: xxx
List-Unsubscribe: <xxx.com/>, <mailto:>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
X-Test-Header: TestHeader
X-Testing: Testee
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Hello from <b>Gmail</b>
";
using MemoryStream memoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(message));
MimeMessage mimeMessage = await MimeMessage.LoadAsync(memoryStream);
string privateKey = ""; // Your private key
byte[] byteArray = Encoding.UTF8.GetBytes(privateKey);
using MemoryStream memory = new MemoryStream(byteArray);
string domain = "xxx"; // Your Domain
string selector = "xxx"; // Selector
DkimSigner signer = new DkimSigner(memory, domain, selector)
{
HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple,
BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple,
QueryMethod = "dns/txt",
};
mimeMessage.Prepare(EncodingConstraint.SevenBit);
signer.Sign(mimeMessage, new HeaderId[] { HeaderId.From });
Message finalmessage = new Message();
finalmessage.Raw = Base64UrlEncode(mimeMessage.ToString());
var result = await gmail.Users.Messages.Send(finalmessage, "me").ExecuteAsync();
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);;
// Special "url-safe" base64 encode.
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "");
}
Screenshots are posted for both Google and Aws SES. Notice how google returns dkim=neutral (body hash did not verify)
.
Please let us know your thoughts.
Issue previously opened with google https://github.com/googleapis/google-api-dotnet-client/issues/2701
This is my Gmail SMTP Sample with Google Xoauth2 using the Google .net client library
// Copyright 2023 DAIMTO ([Linda Lawton](https://twitter.com/LindaLawtonDK)) : [www.daimto.com](http://www.daimto.com/)
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Util.Store;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
var to = "[email protected]";
// TODO: figure out how to get the users email back from the smtp server without having to request the profile scope.
var from = "[email protected]";
var path = @"C:\Development\FreeLance\GoogleSamples\Credentials\Credentials.json";
var scopes = new[] { "https://mail.google.com/" }; // You can only use this scope to connect to the smtp server.
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromFile(path).Secrets,
scopes,
"GmailSmtpUser",
CancellationToken.None,
new FileDataStore(Directory.GetCurrentDirectory(), true)).Result;
var message = new EmailMessage()
{
From = from,
To = to,
MessageText = "This is a test message using https://developers.google.com/gmail/imap/xoauth2-protocol",
Subject = "Testing GmailSMTP with XOauth2"
};
try
{
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 465, true);
var oauth2 = new SaslMechanismOAuth2 (message.From, credential.Token.AccessToken);
await client.AuthenticateAsync (oauth2, CancellationToken.None);
client.Send(message.GetMessage());
client.Disconnect(true);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
public class EmailMessage
{
public string To { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string MessageText { get; set; }
public MimeMessage GetMessage()
{
var body = MessageText;
var message = new MimeMessage();
message.From.Add(new MailboxAddress("From a user", From));
message.To.Add(new MailboxAddress("To a user", To));
message.Subject = Subject;
message.Body = new TextPart("plain") { Text = body };
return message;
}
}
You need to figure out DKIM the part on your own I have not configured that on my workspace account there are a few questions on stack that might help C# DKIM gmail site:stackoverflow.com