Herkese hayırlı sabahlar düşük seviyeli diller serimizde bugün Rust ile kodlamış olduğumuz bir DLL 'nin C# formu ile bağlantısını kurup mail gönderme işlemini yapacağız. Yapmamız gereken ilk önce herhangi bir klasör içerisinde src adlı klasör açmak. Açılan bu klasör içerisine aşağıdaki kodları girelim.
Kod:
use lettre::message::header::ContentType;
use lettre::transport::smtp::authentication::Credentials;
use lettre::{Message, SmtpTransport, Transport};
use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
use widestring::U16CStr;
// Windows için wide string desteği
#[cfg(windows)]
use std::os::raw::c_void;
// Error codes
const SUCCESS: c_int = 1;
const ERROR_INVALID_PARAMS: c_int = -1;
const ERROR_SMTP_FAILED: c_int = -2;
const ERROR_MESSAGE_BUILD: c_int = -3;
// C-style export functions for C# P/Invoke
/// ANSI string versiyonu (basit test için)
#[no_mangle]
pub extern "C" fn send_mail_ansi(
email_from: *const c_char,
email_to: *const c_char,
subject: *const c_char,
body: *const c_char,
smtp_server: *const c_char,
smtp_port: c_int,
smtp_user: *const c_char,
smtp_pass: *const c_char,
enable_ssl: c_int,
) -> c_int {
// Null pointer kontrolü
if email_from.is_null()
|| email_to.is_null()
|| subject.is_null()
|| body.is_null()
|| smtp_server.is_null()
|| smtp_user.is_null()
|| smtp_pass.is_null()
{
return ERROR_INVALID_PARAMS;
}
// C string'lerini Rust string'lerine çevir
let email_from_str = match unsafe { CStr::from_ptr(email_from) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
let email_to_str = match unsafe { CStr::from_ptr(email_to) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
let subject_str = match unsafe { CStr::from_ptr(subject) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
let body_str = match unsafe { CStr::from_ptr(body) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
let smtp_server_str = match unsafe { CStr::from_ptr(smtp_server) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
let smtp_user_str = match unsafe { CStr::from_ptr(smtp_user) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
let smtp_pass_str = match unsafe { CStr::from_ptr(smtp_pass) }.to_str() {
Ok(s) => s,
Err(_) => return ERROR_INVALID_PARAMS,
};
// Mail gönderme işlemi
send_mail_internal(
email_from_str,
email_to_str,
subject_str,
body_str,
smtp_server_str,
smtp_port,
smtp_user_str,
smtp_pass_str,
enable_ssl != 0,
)
}
/// Unicode string versiyonu (Windows için)
#[no_mangle]
pub extern "C" fn send_mail_unicode(
email_from: *const u16,
email_to: *const u16,
subject: *const u16,
body: *const u16,
smtp_server: *const u16,
smtp_port: c_int,
smtp_user: *const u16,
smtp_pass: *const u16,
enable_ssl: c_int,
) -> c_int {
// Null pointer kontrolü
if email_from.is_null()
|| email_to.is_null()
|| subject.is_null()
|| body.is_null()
|| smtp_server.is_null()
|| smtp_user.is_null()
|| smtp_pass.is_null()
{
return ERROR_INVALID_PARAMS;
}
// Wide string'leri UTF-8'e çevir
let email_from_str = unsafe { U16CStr::from_ptr_str(email_from) }.to_string_lossy();
let email_to_str = unsafe { U16CStr::from_ptr_str(email_to) }.to_string_lossy();
let subject_str = unsafe { U16CStr::from_ptr_str(subject) }.to_string_lossy();
let body_str = unsafe { U16CStr::from_ptr_str(body) }.to_string_lossy();
let smtp_server_str = unsafe { U16CStr::from_ptr_str(smtp_server) }.to_string_lossy();
let smtp_user_str = unsafe { U16CStr::from_ptr_str(smtp_user) }.to_string_lossy();
let smtp_pass_str = unsafe { U16CStr::from_ptr_str(smtp_pass) }.to_string_lossy();
// Mail gönderme işlemi
send_mail_internal(
&email_from_str,
&email_to_str,
&subject_str,
&body_str,
&smtp_server_str,
smtp_port,
&smtp_user_str,
&smtp_pass_str,
enable_ssl != 0,
)
}
/// Önceden tanımlanmış değerlerle hızlı test
#[no_mangle]
pub extern "C" fn send_test_mail() -> c_int {
send_mail_internal(
"MAİ[email protected]",
"MAİL",
"Test Mail from Rust",
"Merhaba, bu Rust'tan gönderilen bir test mailidir.",
"smtp.gmail.com",
587,
"MAİ[email protected]",
"ŞİFRE",
true,
)
}
/// Internal mail gönderme fonksiyonu
fn send_mail_internal(
email_from: &str,
email_to: &str,
subject: &str,
body: &str,
smtp_server: &str,
smtp_port: c_int,
smtp_user: &str,
smtp_pass: &str,
enable_ssl: bool,
) -> c_int {
// Tokio runtime oluştur
let rt = match tokio::runtime::Runtime::new() {
Ok(rt) => rt,
Err(_) => return ERROR_SMTP_FAILED,
};
rt.block_on(async {
// Email mesajını oluştur
let email = match Message::builder()
.from(email_from.parse().unwrap())
.to(email_to.parse().unwrap())
.subject(subject)
.header(ContentType::TEXT_PLAIN)
.body(String::from(body))
{
Ok(email) => email,
Err(_) => return ERROR_MESSAGE_BUILD,
};
// SMTP transport oluştur
let creds = Credentials::new(smtp_user.to_string(), smtp_pass.to_string());
let mailer = if enable_ssl {
SmtpTransport::starttls_relay(smtp_server)
.unwrap()
.credentials(creds)
.port(smtp_port as u16)
.build()
} else {
SmtpTransport::builder_dangerous(smtp_server)
.credentials(creds)
.port(smtp_port as u16)
.build()
};
// Mail gönder
match mailer.send(&email) {
Ok(_) => SUCCESS,
Err(_) => ERROR_SMTP_FAILED,
}
})
}
/// DLL yüklendiğinde çağrılır
#[cfg(windows)]
#[no_mangle]
pub extern "system" fn DllMain(_hinst: c_void, _reason: u32, _reserved: c_void) -> i32 {
1
}
Daha sonra src adlı klasörden çıkarak ana klasörümüze geri gelelim & cargo.toml adlı bir dosya açalım. Açılan bu dosya içerisine aşağıdaki satıları yazalım.
Kod:
[package]
name = "smtp_mail_sender"
version = "0.1.0"
edition = "2021"
[lib]
name = "smtp_mail_sender"
crate-type = ["cdylib"]
[dependencies]
lettre = "0.11"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
libc = "0.2"
widestring = "1.0"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
Aynı klasör üzerinde son olarak bir bat dosyası oluşturalım & içerisine şu komutları girelim. Komutları girdikten sonra bat dosyasını çalıştırarak DLL oluşturma işlemimizi başlatalım.
Kod:
@echo off
echo Building SMTP Mail Sender Rust DLL...
REM Rust toolchain gerekli
REM rustup install stable
REM rustup default stable
REM rustup target add x86_64-pc-windows-msvc
echo Checking Rust installation...
rustc --version
if %errorlevel% neq 0 (
echo ERROR: Rust not found. Please install Rust from https://rustup.rs/
pause
exit /b 1
)
echo.
echo Building release DLL...
cargo build --release --target x86_64-pc-windows-msvc
if %errorlevel%==0 (
echo.
echo DLL successfully built!
echo Location: target\x86_64-pc-windows-msvc\release\smtp_mail_sender.dll
echo.
echo Copying DLL to current directory...
copy target\x86_64-pc-windows-msvc\release\smtp_mail_sender.dll .
echo.
echo Files created:
dir smtp_mail_sender.*
) else (
echo.
echo Build failed with error code: %errorlevel%
)
pause
Artık DLL dosyamız klasörümüz üzerinde oluşmuş bulunmakta. Şimdiyse bir adet C# formu oluşturalım & konfigürasyon(Yapılandırma Yöneticisi) ayarlarından Platform seçeneğini x64 olarak seçelim. Seçme işlemini gerçekleştirdikten sonra oluşturmuş olduğumuz DLL 'yi C# projemizin oluştuğu klasör üzerinden bin --> x64 --> Debug içerisine atalım & formumuz üzerinde aşağıdaki süreçleri takip edelim.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Text;
using System.Threading.Tasks;
partial class altına girilecek kodlar yani DLL 'miz & fonksiyonlarının forma tanımlanması işlemi.
C#:
[DllImport("smtp_mail_sender.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int send_mail_ansi(
string emailFrom,
string emailTo,
string subject,
string body,
string smtpServer,
int smtpPort,
string smtpUser,
string smtpPass,
int enableSsl
);
[DllImport("smtp_mail_sender.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern int send_mail_unicode(
string emailFrom,
string emailTo,
string subject,
string body,
string smtpServer,
int smtpPort,
string smtpUser,
string smtpPass,
int enableSsl
);
[DllImport("smtp_mail_sender.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int send_test_mail();
const int SUCCESS = 1;
const int ERROR_INVALID_PARAMS = -1;
const int ERROR_SMTP_FAILED = -2;
const int ERROR_MESSAGE_BUILD = -3;
Ardından formumuza 1 adet buton, 8 adet Textbox, 1 adet ListBox, 1 adette CheckBox ekleyelim.
Textbox adlarımız; txtTo (Mailin kime gideceği), txtFrom (Mailin kimden geldiği), txtSubject (Mail başlığı), txtPort (465, 587 gibi), txtBody (Mail içeriği), txtServer (STMP Adresi), txtUser (Mail adresi), txtPass (Şifre)
CheckBox adımız, ChkSsl (SSL Kontrolü için)
ListBox adımız; txtLog (Mail giderken hata oluştuysa veya oluşmadıysa belirtmek için)
Buton kodlarımız.
C#:
try
{
int port = int.Parse(txtPort.Text);
int result = send_mail_unicode(
txtFrom.Text,
txtTo.Text,
txtSubject.Text,
txtBody.Text,
txtServer.Text,
port,
txtUser.Text,
txtPass.Text,
chkSsl.Checked ? 1 : 0
);
LogResult(result, "Custom mail");
}
catch (Exception ex)
{
LogMessage($"Error: {ex.Message}");
}
Mailin başarılı olup olmadığını belirleyen kodlar.
C#:
private void LogResult(int result, string mailType)
{
string message;
switch (result)
{
case SUCCESS:
message = $"✓ {mailType} başarıyla gönderildi!";
break;
case ERROR_INVALID_PARAMS:
message = $"✗ {mailType} - Geçersiz parametreler";
break;
case ERROR_SMTP_FAILED:
message = $"✗ {mailType} - SMTP hatası";
break;
case ERROR_MESSAGE_BUILD:
message = $"✗ {mailType} - Mesaj oluşturma hatası";
break;
default:
message = $"✗ {mailType} - Bilinmeyen hata: {result}";
break;
}
LogMessage(message);
}
Logların form nesnesi içerisinde gösterilmesini sağlayan kod.
C#:
private void LogMessage(string message)
{
txtLog.Items.Add($"{DateTime.Now:HH:mm:ss} - {message}\n");
}
Deneyelim bakalım mail gelmiş mi?
[ GÖRSEL GÖSTERİM ]
Görüldüğü üzere başarılı teşekkürler.
Görüldüğü üzere başarılı teşekkürler.
