การลงนามอีเมลด้วย DKIM เพื่อการตรวจสอบและการส่งต่อที่ดี
DKIM (DomainKeys Identified Mail, RFC 6376) ทำให้เจ้าของโดเมนสามารถแนบลายเซ็นเข้ารหัสกับอีเมลที่ส่งออก เซิร์ฟเวอร์รับจะดึงกุญแจสาธารณะที่ตรงกับ DNS, คำนวณแฮชใหม่, และยืนยันสองสิ่งพร้อมกัน: เนื้อหาข้อความไม่ถูกแก้ไขระหว่างการส่ง, และข้อความจริง ๆ มาจากผู้ส่งที่ได้รับอนุญาตจากโดเมน หากไม่มี DKIM ผู้ให้บริการสมัยใหม่ (Gmail, Microsoft 365, Yahoo) จะทำเครื่องหมายเมลเป็นสแปม, ทิ้งอย่างเงียบ, หรือปฏิเสธการส่ง — DKIM ไม่ได้เป็นตัวเลือกอีกต่อไปสำหรับเมลการผลิต
คู่มือฉบับนี้เป็นการเดินผ่านขั้นตอนเต็มของ Aspose.Emailเนมสเปซ DKIM ของ ’ สำหรับ .NET ทุกบล็อกโค้ดในบทความนี้มาจากตัวอย่างที่ทำงานได้ใน DKIMExamples โครงการและได้รับการตรวจสอบครบวงจรกับไลบรารี
ข้อกำหนดเบื้องต้น
ประเภท DKIM อยู่ใน Aspose.Email.DKIM เนมสเปซและจัดส่งเฉพาะกับบิลด์ .NET Framework 4.0/4.5 ของไลบรารี พวกมันถูกตัดออกโดยเจตนาจากแพคเกจ .NET Standard 2.0 และ .NET 6/8 เพื่อทำตามตัวอย่างด้านล่าง โปรเจกต์ของคุณต้องอ้างอิง assembly Aspose.Email ที่สร้างสำหรับ net45 (เป้าหมาย net48 ในส่วนที่ใช้งาน .csproj).
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="Aspose.Email">
<HintPath>..\path\to\net45\Aspose.Email.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
คุณยังต้องการคู่คีย์ RSA คีย์ส่วนตัวจะถูกเก็บในแอปพลิเคชันของคุณและใช้ในการเซ็น; คีย์สาธารณะจะถูกเผยแพร่เป็นบันทึก DNS TXT เพื่อให้ผู้รับตรวจสอบ คีย์ 2048 บิตเป็นมาตรฐานในวันนี้:
openssl genrsa -out sample-private-key.pem 2048
ของ Aspose PemReader รับทั้ง PKCS#1 (-----BEGIN RSA PRIVATE KEY-----) และ PKCS#8 (-----BEGIN PRIVATE KEY-----) ไฟล์ที่จัดรูปแบบ
| คลาส | บทบาท | |——-|——| | DKIMSignatureInfo | อธิบายลายเซ็น: selector, domain, อัลกอริทึมแฮช, การทำ canonicalization, และหัวเรื่องที่ครอบคลุม | | PemReader | โหลด RSA private key จากไฟล์หรือสตรีมที่เป็น PEM ลงใน RSACryptoServiceProvider. |
| MailMessage.DKIMSign(rsa, info) | เมธอดส่วนขยาย/อินสแตนซ์ที่คืนสำเนาข้อความที่เซ็นพร้อมกับ DKIM-Signature หัวเรื่องถูกเติมเต็ม | | DkimVerifier | ทำการตรวจสอบด้วย DNS ของข้อความที่เซ็น — ไฟล์, สตรีม, ซิงค์ หรืออะซิงค์ |
กระบวนการเต็มคือ: โหลดคีย์ → อธิบายลายเซ็น → สร้างข้อความ → เซ็น → (เลือก) ตรวจสอบ.
ตัวอย่างการเซ็นแบบขั้นต่ำ
นี่คือโค้ดที่สั้นที่สุดที่สร้างข้อความที่เซ็น DKIM ได้อย่างถูกต้อง:
// Load private key from PEM file
var rsa = PemReader.GetPrivateKey(PrivateKeyPath);
// Create DKIM signature information
var signInfo = new DKIMSignatureInfo("dkim", "example.com")
{
// Default: Relaxed/Relaxed canonicalization
// Default: RSASha1 hash algorithm
};
// Add headers to sign
signInfo.Headers.Add("From");
signInfo.Headers.Add("To");
signInfo.Headers.Add("Subject");
// Create a test email
var mailMessage = new MailMessage(
"sender@example.com",
"recipient@example.com",
"Test Subject",
"This is a test email body signed with DKIM.")
{
From = new MailAddress("sender@example.com", "Sender Name")
};
// Sign the message
var signedMsg = mailMessage.DKIMSign(rsa, signInfo);
// Save the signed message
string outputPath = Path.Combine(DataDir, "basic-signed.eml");
signedMsg.Save(outputPath);
Console.WriteLine($"DKIM-Signature header: {signedMsg.Headers["DKIM-Signature"]?.Substring(0, 50)}...");
สองอาร์กิวเมนต์ของ DKIMSignatureInfo — "dkim" และ "example.com" — คือ selector และ domain. ทั้งสองบอกผู้รับให้ค้นหากุญแจสาธารณะของคุณที่: บันทึก DNS TXT dkim._domainkey.example.com. เลือกชื่อ selector สั้น ๆ (ส่วนมากคือ default, mail, หรือวันที่เช่น 2026jan); ตัวเลือกทำให้คุณหมุนคีย์โดยไม่ต้องทิ้งคีย์เก่า
รายละเอียดสำคัญ: DKIMSign คืนค่า ใหม่ MailMessage instance พร้อมกับ DKIM-Signature หัวเรื่องถูกเพิ่มแล้ว ข้อความต้นฉบับไม่ได้เปลี่ยนแปลง บันทึกหรือส่งอ็อบเจกต์ที่ส่งคืน ไม่ใช้อินพุต
การเลือกหัวเรื่องที่จะเซ็น
หัวเรื่องที่ระบุใน signInfo.Headers เป็นหัวข้อเดียวที่ค่าถูกผูกกับลายเซ็น. สิ่งที่ไม่ได้ระบุสามารถถูกเปลี่ยนแปลงโดยรีเลย์โดยไม่ทำลายลายเซ็น, ซึ่งบางครั้งอาจต้องการ (เช่น Received: หัวข้อที่เพิ่มในขั้นตอนต่อม) และบางครั้งอาจเป็นอันตราย (เช่น การทิ้ง From ที่ไม่มีลายเซ็นทำให้ลายเซ็นไร้ความหมาย).
กฎโดยรวม: ควรลงนามเสมอ From, To, Subject, Date. From โดยเฉพาะจำเป็นสำหรับการจัดแนว DMARC.
var signInfo = new DKIMSignatureInfo("dkim2", "example.com")
{
Headers =
{
"From",
"To",
"Subject",
"Date",
"MIME-Version"
}
};
// Create email with additional headers
var mailMessage = new MailMessage(
"sender@example.com",
"recipient@example.com",
"Custom Headers Test",
"This message includes custom headers in the DKIM signature.")
{
From = new MailAddress("sender@example.com", "Sender"),
Date = DateTime.UtcNow
};
// Ensure headers listed in DKIM signature are present on the message
mailMessage.Headers.Add("MIME-Version", "1.0");
mailMessage.Headers.Add("X-Custom-Header", "CustomValue");
// Sign with custom headers
var signedMsg = mailMessage.DKIMSign(rsa, signInfo);
string outputPath = Path.Combine(DataDir, "custom-headers-signed.eml");
signedMsg.Save(outputPath);
หากคุณระบุ Date แต่ไม่ควรตั้งค่า mailMessage.Date, DKIMSign ขว้าง The following headers to be signed do not exist: Date. เพิ่มหัวข้อทั้งหมดก่อน, จากนั้นลงนาม.
อัลกอริธึมแฮช — RSA‑SHA1 vs RSA‑SHA256
DKIM รองรับอัลกอริธึมการลงนามสองแบบ ค่าเริ่มต้นใน Aspose.Email คือ RSASha1 เพื่อความเข้ากันได้ย้อนหลัง, แต่ การปรับใช้ใหม่ทุกครั้งควรใช้ RSASha256. ผู้ให้บริการหลายรายตอนนี้ทำเครื่องหมายลายเซ็น SHA-1 ว่าไม่ถูกต้องแม้จะตรวจสอบเชิง криптограф ได้.
// Example with RSASha1 (older, less secure but widely supported)
var signInfoSha1 = new DKIMSignatureInfo("dkim-sha1", "example.com")
{
HashAlgorithm = DKIMHashAlgorithm.RSASha1,
Headers = { "From", "To", "Subject" }
};
var mailMessage1 = new MailMessage(
"sender@example.com",
"recipient@example.com",
"SHA1 Test",
"Signed with RSASha1 algorithm.");
mailMessage1.From = new MailAddress("sender@example.com");
var signedMsgSha1 = mailMessage1.DKIMSign(rsa, signInfoSha1);
string pathSha1 = Path.Combine(DataDir, "sha1-signed.eml");
signedMsgSha1.Save(pathSha1);
// Example with RSASha256 (newer, more secure)
var signInfoSha256 = new DKIMSignatureInfo("dkim-sha256", "example.com")
{
HashAlgorithm = DKIMHashAlgorithm.RSASha256,
Headers = { "From", "To", "Subject" }
};
var mailMessage2 = new MailMessage(
"sender@example.com",
"recipient@example.com",
"SHA256 Test",
"Signed with RSASha256 algorithm.");
mailMessage2.From = new MailAddress("sender@example.com");
var signedMsgSha256 = mailMessage2.DKIMSign(rsa, signInfoSha256);
string pathSha256 = Path.Combine(DataDir, "sha256-signed.eml");
signedMsgSha256.Save(pathSha256);
ผลลัพธ์ที่ได้ DKIM-Signature หัวข้อโฆษณาอัลกอริธึมผ่าน a= แท็ก (a=rsa-sha1 เทียบกับ a=rsa-sha256). ผู้รับจะใช้แท็กนั้นเพื่อเลือกแฮชที่จะคำนวณใหม่.
การทำให้มาตรฐาน — Simple กับ Relaxed
การทำให้มาตรฐานคือวิธีที่ DKIM ตกลงรูปแบบข้อความที่เสถียรและเท่ากันเป็นไบต์ก่อนการแฮช มีอัลกอริธึมสองแบบสำหรับหัวข้อและเนื้อหาแยกกัน:
Simple— เกือบไม่มีการทำให้เป็นมาตรฐาน. บรรทัดว่างสุดท้ายในเนื้อหาถูกลบ, แต่ช่องว่างอื่น ๆ ไม่ถูกแก้ไข. ช่องว่างเดียวที่เพิ่มโดยรีเลย์จะทำให้ลายเซ็นไม่ถูกต้อง.Relaxed— พับช่องว่างภายในค่าหัวข้อ, แปลงชื่อหัวข้อเป็นตัวพิมพ์เล็ก, และบีบอัดช่องว่างต่อเนื่องในเนื้อหา. ทนต่อการจัดรูปแบบเล็กน้อยที่เอเย่นต์ส่งเมลทำ.
เลือก Relaxed สำหรับหัวข้อและเนื้อหา ทั้งสองกรณี ยกเว้นกรณีที่คุณมีเหตุผลเฉพาะ ไม่ควรทำ ส่วนใหญ่การ deploy ในการผลิตทำเช่นนั้น.
// Simple canonicalization - almost no changes allowed
var signInfoSimple = new DKIMSignatureInfo("dkim-simple", "example.com")
{
HeaderCanonicalization = CanonicalizationType.Simple,
BodyCanonicalization = CanonicalizationType.Simple,
Headers = { "From", "To", "Subject" }
};
var mailMessage1 = new MailMessage(
"sender@example.com",
"recipient@example.com",
"Simple Canonicalization",
"This message uses Simple canonicalization.");
mailMessage1.From = new MailAddress("sender@example.com");
var signedSimple = mailMessage1.DKIMSign(rsa, signInfoSimple);
string pathSimple = Path.Combine(DataDir, "simple-canonical.eml");
signedSimple.Save(pathSimple);
// Relaxed canonicalization - minor changes allowed (whitespace normalization)
var signInfoRelaxed = new DKIMSignatureInfo("dkim-relaxed", "example.com")
{
HeaderCanonicalization = CanonicalizationType.Relaxed,
BodyCanonicalization = CanonicalizationType.Relaxed,
Headers = { "From", "To", "Subject" }
};
var mailMessage2 = new MailMessage(
"sender@example.com",
"recipient@example.com",
"Relaxed Canonicalization",
"This message uses Relaxed canonicalization.");
mailMessage2.From = new MailAddress("sender@example.com");
var signedRelaxed = mailMessage2.DKIMSign(rsa, signInfoRelaxed);
string pathRelaxed = Path.Combine(DataDir, "relaxed-canonical.eml");
signedRelaxed.Save(pathRelaxed);
การทำให้มาตรฐานของหัวข้อและเนื้อหามีอิสระ — relaxed/simple เป็นการผสมผสานที่สมบูรณ์แบบ, เขียนแบบนั้นใน c= แท็กของหัวข้อ DKIM.
การโหลดคีย์ส่วนตัว
PemReader จัดการการเข้ารหัส PEM ทั้งสองแบบอย่างโปร่งใส ไม่มี Pkcs1Reader / Pkcs8Reader — เพียงแค่ส่งพาธหรือสตรีม:
// Check if private key file exists
if (!File.Exists(PrivateKeyPath))
{
Console.WriteLine($"Private key file not found: {PrivateKeyPath}");
Console.WriteLine("Creating a sample private key for demonstration...");
// Create a sample RSA key (for testing only - in production, use real keys)
using var rsa = new System.Security.Cryptography.RSACryptoServiceProvider(2048);
var privateKeyParams = rsa.ExportParameters(true);
Console.WriteLine("Sample RSA key created (2048 bits).");
Console.WriteLine("In production, load your actual private key from a secure location.");
Console.WriteLine("PEM file format should contain either:");
Console.WriteLine(" - BEGIN RSA PRIVATE KEY (PKCS#1)");
Console.WriteLine(" - BEGIN PRIVATE KEY (PKCS#8)");
}
else
{
// Load the private key
var rsa = PemReader.GetPrivateKey(PrivateKeyPath);
Console.WriteLine($"Private key loaded successfully from: {PrivateKeyPath}");
Console.WriteLine("Key size: 2048 bits (typical for DKIM)");
}
Console.WriteLine("\nPEM File Format Examples:");
Console.WriteLine("--------------------------");
Console.WriteLine("PKCS#1 format:");
Console.WriteLine("-----BEGIN RSA PRIVATE KEY-----");
Console.WriteLine("MIIEpAIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyF8PbnGy...");
Console.WriteLine("-----END RSA PRIVATE KEY-----");
Console.WriteLine();
Console.WriteLine("PKCS#8 format:");
Console.WriteLine("-----BEGIN PRIVATE KEY-----");
Console.WriteLine("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...");
Console.WriteLine("-----END PRIVATE KEY-----");
PemReader.GetPrivateKey ส่งคืนอ็อบเจกต์ RSACryptoServiceProvider พร้อมมอบให้ DKIMSign. มีอีกหนึ่ง GetPrivateKey(Stream) โอเวอร์โหลดสำหรับกรณีที่คีย์มาจาก vault คีย์, blob ที่เข้ารหัส, หรือทรัพยากรฝังแทนไฟล์ระบบ.
กฎการจัดการคีย์:
- ห้ามคอมมิตคีย์ส่วนตัวเข้าสู่ระบบควบคุมเวอร์ชัน.
*.pemอยู่ใน.gitignore. - ในสภาพการผลิต, โหลดคีย์จากตัวจัดการความลับ (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault) ไม่ใช่จากดิสก์.
- หมุนคีย์ทุก 6–12 เดือน เผยแพร่วัสดุตัวเลือกใหม่ก่อน, สลับการลงนาม, แล้วถอนบันทึก DNS เก่าหลังระยะเวลาผ่อนผัน.
การตรวจสอบข้อความที่ลงนามจากไฟล์
การตรวจสอบเป็นการดำเนินการสมมาตร: ให้ลายเซ็นที่ลงนาม .eml, DkimVerifier ดึง DKIM-Signature หัวข้อ, ทำการค้นหา DNS กับ <selector>._domainkey.<domain> สำหรับคีย์สาธารณะ, และคำนวณแฮชใหม่ ผลลัพธ์คือ DkimResult กับ IsValid และ ErrorMessage.
// For this example, we need a signed message
if (!File.Exists(signedMessagePath))
{
Console.WriteLine($"Signed message file not found: {signedMessagePath}");
Console.WriteLine("Please provide a DKIM-signed .eml file for verification.");
return;
}
// Verify the signature
DkimResult result = DkimVerifier.Verify(signedMessagePath);
// Check the result
if (result.IsValid)
{
Console.WriteLine("[OK] DKIM signature verification successful!");
Console.WriteLine("The message was signed by the claimed domain.");
}
else
{
Console.WriteLine("[FAIL] DKIM signature verification failed!");
Console.WriteLine($"Error: {result.ErrorMessage}");
}
Console.WriteLine("\nVerification Process:");
Console.WriteLine("1. Extracts DKIM-Signature header from the message");
Console.WriteLine("2. Queries DNS for the public key (selector._domainkey.domain)");
Console.WriteLine("3. Verifies the signature using the public key");
Console.WriteLine("4. Compares computed body hash with the signed body hash");
การตรวจสอบข้อความที่ลงนามด้วย
d=example.comจะล้มเหลวเสมอด้วย "key not in dictionary" หรือข้อผิดพลาด DNS‑lookup ที่คล้ายกัน เพราะexample.comไม่ได้เผยแพร่บันทึก DKIM ใช้โดเมนที่คุณควบคุม (หรือข้อความทดสอบที่รู้ว่าดี) เพื่อทดสอบการตรวจสอบจริง.
การตรวจสอบจากสตรีม
เมื่อข้อความไม่ได้อยู่บนดิสก์ — มาจากการดึง IMAP, คิว, การอัปโหลด HTTP หรือที่เก็บ blob — ใช้ Stream โอเวอร์โหลด. ยอมรับสตรีมอ่านที่สามารถหาตำแหน่งได้ใดก็ได้:
// Load the signed message into a stream
using (var stream = File.OpenRead(signedMessagePath))
{
DkimResult result = DkimVerifier.Verify(stream);
if (result.IsValid)
{
Console.WriteLine("[OK] DKIM signature verified successfully from stream!");
}
else
{
Console.WriteLine("[FAIL] Verification failed!");
Console.WriteLine($"Error: {result.ErrorMessage}");
}
}
Console.WriteLine("\nStream-based verification is useful when:");
Console.WriteLine(" - Working with email from IMAP/POP3 clients");
Console.WriteLine(" - Processing emails from databases or cloud storage");
Console.WriteLine(" - Building web applications that receive emails via HTTP");
Verify(Stream) และ Verify(string) ทำงานแบบเดียวกัน — ทั้งสองบล็อกจนกว่าการค้นหา DNS จะเสร็จ สำหรับอะไรที่ผู้ใช้เห็น, ใช้เวอร์ชันอะซิงค์ด้านล่าง.
การตรวจสอบแบบอะซิงค์
การตรวจสอบ DKIM ต้องใช้การเดินทางรอบ DNS ซึ่งอาจใช้หลายสิบมิลลิวินาทีแม้บนเครือข่ายที่เร็ว ภายในตัวจัดการคำขอ ASP.NET, ลูปการประมวลผลข้อความ หรือเธรด UI ใด ๆ การใช้เวลานี้สะสมได้เร็ว. VerifyAsync คืนค่า Task<DkimResult> ว่าคุณสามารถ await:
if (!File.Exists(signedMessagePath))
{
Console.WriteLine("Signed message file not found.");
return;
}
// Async verification
DkimResult result = await DkimVerifier.VerifyAsync(signedMessagePath);
if (result.IsValid)
{
Console.WriteLine("[OK] Async verification successful!");
}
else
{
Console.WriteLine("[FAIL] Async verification failed!");
Console.WriteLine($"Error: {result.ErrorMessage}");
}
Console.WriteLine("\nAsync verification is recommended for:");
Console.WriteLine(" - Web applications (ASP.NET, etc.)");
Console.WriteLine(" - Services that process multiple emails");
Console.WriteLine(" - Any application where you want to avoid blocking the main thread");
ยังมี VerifyAsync(Stream) โอเวอร์โหลด. เช่นเดียวกับ API แบบซิงค์ เมธอดประกาศ async Task (ไม่ async void) — จุดเรียกควร await มัน, และจุดเริ่มต้นแอปคอนโซลสามารถทำ VerifySignatureAsync().GetAwaiter().GetResult() เมื่อมี async Main ไม่พร้อมให้บริการ.
จากต้นถึงปลาย: โหลด, ลงนาม, บันทึก, ตรวจสอบ
ชิ้นส่วนด้านบนรวมกันเป็นกระบวนการทำงานเดียว นี่คือสายการทำงานการลงนามและตรวจสอบเต็มที่คุณจะฝังเข้าในบริการอีเมลเชิงธุรกรรม:
// Step 1: Load private key
var rsa = PemReader.GetPrivateKey(PrivateKeyPath);
// Step 2: Create signature information
var signInfo = new DKIMSignatureInfo("dkim", "example.com")
{
HeaderCanonicalization = CanonicalizationType.Relaxed,
BodyCanonicalization = CanonicalizationType.Relaxed,
HashAlgorithm = DKIMHashAlgorithm.RSASha256,
Headers =
{
"From",
"To",
"Subject",
"Date",
"MIME-Version"
}
};
// Step 3: Create email message
var mailMessage = new MailMessage(
"john.doe@example.com",
"jane.smith@example.org",
"Important Document - DKIM Signed",
"Please find the attached document.\n\nBest regards,\nJohn Doe");
mailMessage.From = new MailAddress("john.doe@example.com", "John Doe");
mailMessage.To.Add(new MailAddress("jane.smith@example.org", "Jane Smith"));
mailMessage.Date = DateTime.UtcNow;
mailMessage.Headers.Add("MIME-Version", "1.0");
// Step 4: Sign the message
var signedMessage = mailMessage.DKIMSign(rsa, signInfo);
// Step 5: Save the signed message
string signedPath = Path.Combine(DataDir, "end-to-end-signed.eml");
signedMessage.Save(signedPath);
// Step 6: Verify the signature
var result = DkimVerifier.Verify(signedPath);
if (result.IsValid)
{
Console.WriteLine(" [OK] Signature verification successful!");
Console.WriteLine(" [OK] The message integrity is confirmed.");
Console.WriteLine(" [OK] The sender domain is authenticated.");
}
else
{
Console.WriteLine($" [FAIL] Verification failed: {result.ErrorMessage}");
}
// Step 7: Display DKIM-Signature header
Console.WriteLine("\nStep 7: DKIM-Signature header:");
Console.WriteLine(" " + signedMessage.Headers["DKIM-Signature"]);
ชุดเต็ม DKIM-Signature หัวข้อที่โค้ดนี้สร้างออกมามีลักษณะดังนี้:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
h=from:to:subject:date:mime-version; q=dns/txt; s=dkim; t=1780252880;
bh=e2RkwEm0k0yLcVmhi3KeXpt14Ppx3Xx49S33/+J8OGc=;
b=Zd3sfCGGD9YdOLw1o3YHLFs7DO6V9cc7anye5E3kQ/MEdkU14daTru0sXTZCtCryvJubCs...
แท็กที่น่าสนใจ:
v=1— เวอร์ชัน DKIM.a=rsa-sha256— อัลกอริธึม; สะท้อนHashAlgorithm.c=relaxed/relaxed— การทำให้เป็นมาตรฐาน (หัวข้อ/เนื้อหา).d=example.com/s=dkim— ตัวเลือกและโดเมน; รวมกันจะเป็นชื่อการค้นหา DNS.h=from:to:subject:date:mime-version— หัวข้อที่ลงนามตามลำดับ.bh=— แฮช base64 ของเนื้อหาที่ทำให้เป็นมาตรฐาน.b=— ลายเซ็น RSA จริงที่คำนวนจากหัวข้อที่ทำให้เป็นมาตรฐาน.
หากคุณเปลี่ยนค่าหัวข้อที่ลงนามใด ๆ หรือแก้ไขเนื้อหา, bh และ b ไม่ตรงกันแล้วและการตรวจสอบล้มเหลว.
การเผยแพร่คีย์สาธารณะใน DNS
การลงนามในเครื่องเป็นเพียงครึ่งหนึ่งของงาน เพื่อให้ผู้รับตรวจสอบได้ คีย์สาธารณะของ RSA ของคุณต้องถูกเผยแพร่เป็นบันทึก DNS TXT ที่ <selector>._domainkey.<domain>:
Record: dkim._domainkey.example.com
Type: TXT
Value: v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBC...
ดึงคีย์สาธารณะจาก PEM ของคุณด้วย OpenSSL:
openssl rsa -in sample-private-key.pem -pubout -out sample-public-key.pem
ลบบรรทัดหัว/ท้ายและเชื่อมต่อเนื้อหา base64 สำหรับ p= ค่า. จากนั้นยืนยันว่าบันทึกใช้งานได้ก่อนพึ่งพา:
dig dkim._domainkey.example.com TXT
เครื่องมือออนไลน์เช่น DKIM Validator และ MXToolbox DKIM Checker จะบอกคุณว่าข้อความจริงที่คุณส่งสามารถตรวจสอบได้จากต้นถึงปลายหรือไม่ ใช้ก่อนที่จะเปลี่ยนการจราจรผลิตจริง.