نصب و پیکربندی Postfix برای ارسال ایمیل - قسمت ۱۰ - ارسال ایمیل از یک برنامه #C در لینوکس با Postfix
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۲۳ ۱۰:۱۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
main.cf و پارامترهای کلیدی آن بیشتر آشنا شویم تا بتوانیم بر اساس «تحلیل پیکربندی امنیتی Postfix» پارامترهای MailKit را تنظیم کنیم.main.cf و پارامترهای کلیدیmain.cf در ارتباط بودهایم. این فایل، مغز متفکر و مرکز فرماندهی Postfix است. درک صحیح ساختار و پارامترهای مهم آن، به شما قدرت و انعطافپذیری لازم برای پیکربندی هر نوع سناریوی ایمیلی را میدهد.main.cf و ابزار postconfmain.cf که در مسیر /etc/postfix/ قرار دارد، فایل پیکربندی اصلی Postfix است. ساختار این فایل بسیار ساده است:parameter = value
# شروع میشوند، به عنوان کامنت در نظر گرفته شده و نادیده گرفته میشوند.nano یا vim میتواند منجر به خطاهای نوشتاری شود. ابزار استاندارد و امن برای کار با این فایل، دستور postconf است.postconf:postconf myhostname
postconf -n
postconf -d
postconf:-e (مخفف edit) استفاده میکنیم. این روش از بروز خطا جلوگیری میکند.sudo postconf -e "myorigin = \$mydomain"
\ قبل از $ برای جلوگیری از تفسیر آن توسط Shell ضروری است.)main.cf، باید از Postfix بخواهیم که تنظیمات جدید را بازخوانی کند:sudo postfix reload
myhostnameHELO یا EHLO) استفاده میکند.mail.yourdomain.commydomainmyhostname استخراج میکند.myhostname برابر mail.yourdomain.com باشد، mydomain به صورت خودکار yourdomain.com در نظر گرفته میشود.myorigin$myhostname (یعنی ایمیل کاربر root به صورت root@mail.yourdomain.com ارسال میشود).$mydomain قرار میدهند (myorigin = $mydomain) تا ایمیلها تمیزتر و به صورت root@yourdomain.com ارسال شوند.inet_interfacesall (به تمام آدرسهای IP عمومی و محلی سرور گوش میدهد).loopback-only (فقط به 127.0.0.1 گوش میدهد و سرور را از اینترنت ایزوله میکند).relayhostrelayhost = [smtp.sendgrid.net]:587.mynetworks127.0.0.0/8, [::1]/128) و گاهی زیرشبکه محلی سرور است.0.0.0.0/0 را به این لیست اضافه کنید، زیرا سرور شما را به یک Open Relay تبدیل کرده و به سرعت توسط اسپمرها مورد سوءاستفاده قرار میگیرد.mydestination$myhostname, localhost.$mydomain, localhost.yourdomain.com) را به این لیست اضافه میکنید که بخواهید یک سرور ایمیل کامل برای دریافت ایمیلهای آن دامنه راهاندازی کنید.inet_interfaces = loopback-only mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
main.cf تنظیمات Postfix بیندازیم که شما تنظیم کردهاید. درک این تنظیمات به ما نشان میدهد که چرا سرور ما امن است و فقط به برنامههای محلی اجازه ارسال ایمیل میدهد.inet_interfaces = loopback-only127.0.0.1) ارسال میشوند، گوش دهد. این یعنی سرور Postfix شما از اینترنت عمومی یا حتی از کامپیوترهای دیگر در شبکه محلی شما قابل دسترس نیست. مانند یک خط تلفن داخلی است که فقط از داخل ساختمان میتوان با آن تماس گرفت.mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destinationpermit_mynetworks: اگر درخواستی از یک شبکه "خودی" (که در mynetworks تعریف شده) آمد، به آن اجازه ارسال ایمیل به هر مقصدی را بده.permit_sasl_authenticated: اگر کاربری احراز هویت کرده باشد، به او اجازه ارسال بده (در سناریوی ما کاربردی ندارد چون احراز هویت را فعال نکردهایم).defer_unauth_destination: اگر هیچکدام از شرایط بالا برقرار نبود، درخواست را رد کن.127.0.0.1 و پورت استاندارد و غیررمزنگاری شده 25 استفاده خواهیم کرد.dotnet new console
dotnet add package MailKit
SslHandshakeExceptionProgram.cs، کد زیر را برای یک تست اولیه قرار میدهیم.using MailKit.Net.Smtp;
using MimeKit;
Console.WriteLine("Attempting to send an email...");
// ایجاد پیام
var message = new MimeMessage();
message.From.Add(new MailboxAddress("System Reporter", "reporter@dntips.ir"));
message.To.Add(new MailboxAddress("Admin", "admin-email@example.com")); // آدرس گیرنده را تغییر دهید
message.Subject = "A test email from our C# App";
message.Body = new TextPart("plain")
{
Text = @"Hello,
This is a test message sent from our secure local Postfix server.
Regards,
C# App"
};
// ارسال پیام
using var client = new SmtpClient();
try
{
// اتصال به سرور محلی در پورت 25
await client.ConnectAsync("127.0.0.1", 25, false); // اینجا ممکن است خطا رخ دهد
Console.WriteLine("Connected to server...");
await client.SendAsync(message);
Console.WriteLine("Email sent successfully!");
await client.DisconnectAsync(true);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred!");
Console.WriteLine(ex.ToString());
}Unhandled exception. MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection. The host name (127.0.0.1) did not match the name given in the server's SSL certificate (email.dntips.ir). ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
email.dntips.ir صادر شده) به MailKit ارائه میدهد.127.0.0.1 متصل شدهاید، اما گواهی برای email.dntips.ir است.Program.cs به شکل زیر خواهد بود:using MailKit.Net.Smtp;
using MimeKit;
Console.WriteLine("Attempting to send an email...");
var message = new MimeMessage();
message.From.Add(new MailboxAddress("System Reporter", "reporter@dntips.ir"));
message.To.Add(new MailboxAddress("Admin", "admin-email@example.com"));
message.Subject = "A test email from our C# App";
message.Body = new TextPart("plain")
{
Text = @"Hello,
This is a test message sent from our secure local Postfix server.
Regards,
C# App"
};
using var client = new SmtpClient();
try
{
// >>>>> شروع تغییرات <<<<<
// به دلیل اینکه ارتباط کاملا لوکال و مورد اعتماد است،
// ما اعتبارسنجی گواهی SSL سرور را غیرفعال میکنیم.
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.CheckCertificateRevocation = false;
// >>>>> پایان تغییرات <<<<<
// در اینجا صراحتا اعلام میکنیم که از SSL استفاده نشود.
await client.ConnectAsync("127.0.0.1", 25, false);
Console.WriteLine("Connected to server...");
await client.SendAsync(message);
Console.WriteLine("Email sent successfully!");
await client.DisconnectAsync(true);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred!");
Console.WriteLine(ex.ToString());
}client.ServerCertificateValidationCallback = (s, c, h, e) => true;: این خط به MailKit میگوید: "مهم نیست گواهی SSL سرور چه بود، چه مشکلی داشت، یا با چه نامی صادر شده بود؛ آن را همیشه قبول کن."client.CheckCertificateRevocation = false;: این خط، بررسی ابطال گواهی را نیز غیرفعال میکند تا فرآیند اعتبارسنجی سریعتر و سادهتر شود.await client.ConnectAsync("127.0.0.1", 25, false);: ما همچنان به MailKit میگوییم که از ابتدا با SSL شروع نکند.tail -f /var/log/mail.log در ترمینال دیگر، لاگ ارسال موفقیتآمیز ایمیل را مشاهده کنید.ServerCertificateValidationCallback) یک اقدام بسیار خطرناک در هنگام اتصال به سرورهای عمومی در اینترنت است و شما را در معرض حملات "مرد میانی" (Man-in-the-Middle) قرار میدهد. ما فقط و فقط به این دلیل این کار را انجام دادیم که ۱۰۰٪ مطمئن هستیم ارتباط ما با 127.0.0.1 یک کانال بسته، داخلی و مورد اعتماد است. هرگز این کد را برای اتصال به یک سرور SMTP خارجی (مانند smtp.gmail.com) استفاده نکنید.appsettings.json قرار دهید و آنها را در کد خود به صورت ثابت (Hardcode) ننویسید.try-catch که در کد قرار دادیم برای شروع خوب است، اما در محیط عملیاتی، باید خطاهای خاصتری مانند SmtpCommandException را مدیریت کنید تا بتوانید دلیل دقیق شکست در ارسال را متوجه شوید.