电子邮件 是最早的互联网应用之一。
一个 电子邮件系统 至少由三部分组成
一封 电子邮件 由两个部分组成
一个 电子邮件地址 由三个部分组成
1*( atext / "." ) "@" ldh-str 1*( "." ldh-str )
/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
总结一下就是 三种协议,一种格式
sendmail
busybox 中的 sendmail
-S
表示SMTP服务器的地址和端口号-au
表示发送邮箱名-ap
表示发送邮箱授权码 sendmail -f from@xx.com -t to@xx.com -S smtp.qq.com:465 -auxxx -apxxxx -s mail.txt
cat mail.txt | sendmail -f from@xx.com -t to@xx.com -S smtp.qq.com:465 -auxxx -apxxxx
使用标准输入的例子
cat <<- EOF | sendmail -f from@xx.com -t to@xx.com -S smtp.qq.com:465 -auxxx -apxxxx
Date: Fri, 5 Apr 2024 06:27:52 +0000
To: bob1@example.com, bob2@example.com, bob3@example.com
From: Mailer <alice@example.com>
Subject: Here is the subject
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
This is the test message
EOF
curl
curl -v --ssl --url 'smtps://smtp.qq.com:465/smtp.qq.com' \
--user 'alice@example.com:NvbQBTZW5kRW' \
--mail-from 'alice@example.com' \
--mail-rcpt 'bob@example.com' \
--login-options AUTH=LOGIN \
--upload-file mail-curl.txt
cat mail-curl.txt | curl -v --ssl --url 'smtps://smtp.qq.com:465/smtp.qq.com' \
--user 'alice@example.com:NvbQBTZW5kRW' \
--mail-from 'alice@example.com' \
--mail-rcpt 'bob@example.com' \
--login-options AUTH=LOGIN \
--upload-file -
从标准输入中读取邮件
cat <<- EOF | curl -v --no-progress-meter --url 'smtp://127.0.0.1:25/NB4045' \
--user 'alice@example.com:NvbQBTZW5kRW' \
--mail-from 'alice@example.com' \
--mail-rcpt 'bob1@example.com' \
--mail-rcpt 'bob2@example.com' \
--mail-rcpt 'bob3@example.com' \
--login-options AUTH=LOGIN \
--upload-file - \
Date: Fri, 5 Apr 2024 06:27:52 +0000
To: bob1@example.com, bob2@example.com, bob3@example.com
From: Mailer <alice@example.com>
Subject: Here is the subject
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
This is the test message
EOF
powershell
Send-MailMessage
Send-MailMessage 不支持 465 端口的 smtps ,如果要使用 smtps 就要改用其他端口
Send-MailMessage -SmtpServer "smtp.qq.com" -Port 587 -UseSsl `
-Credential $(New-Object System.Management.Automation.PSCredential("alice@example.com", $(ConvertTo-SecureString "NvbQBTZW5kRW" -AsPlainText -Force))) `
-From "alice@example.com" `
-To 'User02 <user02@fabrikam.com>', 'User03 <user03@fabrikam.com>' `
-Subject 'Test mail' `
-Body "message"
Send-MailMessage -SmtpServer "127.0.0.1" -Port 587 -UseSsl `
-Credential $(New-Object System.Management.Automation.PSCredential("alice@example.com", $(ConvertTo-SecureString "NvbQBTZW5kRW" -AsPlainText -Force))) `
-From "alice@example.com" `
-To 'User02 <user02@fabrikam.com>', 'User03 <user03@fabrikam.com>' `
-Cc 'Cc02 <Cc02@fabrikam.com>', 'Cc03 <Cc03@fabrikam.com>' `
-Bcc 'Bcc02 <Bcc02@fabrikam.com>', 'Bcc03 <Bcc03@fabrikam.com>' `
-Subject '中文Test mail' `
-Encoding 'utf8' `
-Attachments './v2.php' `
-BodyAsHtml `
-Body "<p>中文mailMessage</p>"
$smtpClient = New-Object System.Net.Mail.SmtpClient("smtp.qq.com", 587)
$smtpClient.EnableSsl = $True
$smtpClient.Credentials = New-Object System.Net.NetworkCredential("alice@qq.com", "NvbQBTZW5kRW")
$smtpClient.Send("alice@qq.com", "user02@fabrikam.com", "Subject", "mailMessage")
<!--
```
$smtpClient = New-Object System.Net.Mail.SmtpClient("127.0.0.1", 25)
$smtpClient.Credentials = New-Object System.Net.NetworkCredential("1643253513@qq.com", "wdgwshjofvvmdeef")
$mailMessage = New-Object System.Net.Mail.MailMessage
$mailMessage.From = New-Object System.Net.Mail.MailAddress("jane@contoso.com", "Jane Clayton")
$mailMessage.To.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso2.com", "Jane Clayton2")))
$mailMessage.To.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso3.com", "Jane Clayton3")))
$mailMessage.CC.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso4.com", "Jane Clayton4")))
$mailMessage.CC.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso5.com", "Jane Clayton5")))
$mailMessage.Bcc.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso6.com", "Jane Clayton6")))
$mailMessage.Bcc.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso7.com", "Jane Clayton7")))$contentType = New-Object System.Net.Mime.ContentType $contentType.Name = 'v2.php' $contentType.MediaType = System.Net.Mime.MediaTypeNames::Text::Plain System.Net.Mail.Attachment('./v2.php', $contentType)
System.Net.Mime.MediaTypeNames.Text.Plain
System.Net.Mime.MediaTypeNames.ToString() System.Net.Mime.MediaTypeNames.Text
Get-Member -MemberType Property System.Net.Mime.MediaTypeNames | Get-Member
System.Net.Mime.MediaTypeNames.Attributes System.Net.Mime.MediaTypeNames.GetEnumNames
如果是完整的类名,静态类,对象,或者已经赋值的变量 [System.Net.Mail.MailAddress] | Get-Member System.Net.Mime.MediaTypeNames | Get-Member $a | Get-Member
System.Net.Mime.MediaTypeNames | Get-Member $a | Get-Member
[AppDomain]::CurrentDomain.GetAssemblies() | ? {$.Location -and ($.Location.Split('\')[-1] -eq 'System.Net.Mime.MediaTypeNames.dll')}
System.AppDomain::CurrentDomain.GetAssemblies() | ForEach-Object { $_.GetTypes() }
System.AppDomain::CurrentDomain.GetAssemblies() | ForEach-Object { $_.GetTypes() } | Select-Object -First 1 | format-list
System.AppDomain::CurrentDomain.GetAssemblies() | Select-Object -First 1 | format-list System.AppDomain::CurrentDomain.GetAssemblies() | Select-Object -First 1 | Get-Member (System.AppDomain::CurrentDomain.GetAssemblies() | Select-Object -First 1 ).GetName() (System.AppDomain::CurrentDomain.GetAssemblies() | Select-Object -First 1 ).GetTypes()
System.AppDomain::CurrentDomain.GetAssemblies() | ForEach-Object { $.GetTypes() } | Select-Object -First 1 | Get-Member -Name Name Where-Object { $.GetName() -eq "System" } | Get-Member
System.AppDomain::CurrentDomain.GetAssemblies() | ForEach-Object { $.GetTypes() } | ForEach-Object { $.GetMethods(‘NonPublic, Public, Static’) } | ForEach-Object { $MethodInfo = $; $.GetCustomAttributes($false) } | Where-Object { $MethodInfo.Name.ToLower() -eq $FunctionName.ToLower() -and $_.Value -eq $Module } | ForEach-Object { $MethodInfo }
这一段是可行的 只能用在 windows powershell $mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? {$.Location -and ($.Location.Split('\')[-1] -eq 'System.dll')} $Win32Native = $mscorlib.GetType('Microsoft.Win32.NativeMethods') $OpenProcessMethod = $Win32Native.GetMethod('OpenProcess', ([Reflection.BindingFlags] 'NonPublic, Public, Static')) $OpenProcessMethod.Invoke($null, @(0x1F0FFF, $False, 524))
这一段是可行的 只能用在 powershell $mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? {$.Location -and ($.Location.Split('\')[-1] -eq 'System.Diagnostics.Process.dll')} $Win32Native = $mscorlib.GetType('Interop+Kernel32') $OpenProcessMethod = $Win32Native.GetMethod('OpenProcess', ([Reflection.BindingFlags] 'NonPublic, Public, Static')) $OpenProcessMethod.Invoke($null, @(0x1F0FFF, $False, 524))
$mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? {$.Location -and ($.Location.Split('\')[-1] -eq 'System.dll')} | Select-Object -ExpandProperty Namespace -Unique
$mailMessage.SubjectEncoding = [System.Text.Encoding]::UTF8
$mailMessage.BodyEncoding = [System.Text.Encoding]::UTF8
$mailMessage.Subject = "中文Subject"
$mailMessage.IsBodyHtml = $True
$mailMessage.Body = "<p>中文mailMessage</p>"
```
- System.Web.Mail
printf "auth\0%s\0%s" "1643253513@qq.com" "wdgwshjofvvmdeef" | base64
$smtpMail = New-Object System.Web.Mail.SmtpMail
Add-Type -AssemblyName "System.Web" [System.Web.Mail.SmtpMail]
Add-Type -AssemblyName "System.Web" 为什么要单独加载 System.Web 程序集? 因为 powershell 没有默认加载 System.Web
什么是程序集? 就是 .NET 的 .dll 文件 程序集采用可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式,是 .NET 应用程序的构建基块 。 它们向公共语言运行时提供了注意类型实现代码所需的信息。
动态链接会按一定的顺序去搜索 https://learn.microsoft.com/zh-cn/windows/win32/dlls/dynamic-link-library-search-order
Add-Type 也可以直接指定 dll 的路径 Add-Type -Path "C:\path\to\your\MyLibrary.dll"
$smtpClient = New-Object System.Net.Mail.SmtpClient("127.0.0.1", 25)
Get-Help Add-Type
$smtpClient = New-Object System.Net.Mail.SmtpClient("smtp.qq.com", 587) $smtpClient.EnableSsl = $True
$smtpClient = New-Object System.Net.Mail.SmtpClient("127.0.0.1", 25) $smtpClient.Credentials = New-Object System.Net.NetworkCredential("1643253513@qq.com", "wdgwshjofvvmdeef") $mailMessage = New-Object System.Net.Mail.MailMessage $mailMessage.From = New-Object System.Net.Mail.MailAddress("jane@contoso.com", "Jane Clayton") $mailMessage.To.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso2.com", "Jane Clayton2"))) $mailMessage.To.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso3.com", "Jane Clayton3"))) $mailMessage.CC.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso4.com", "Jane Clayton4"))) $mailMessage.CC.Add($(New-Object System.Net.Mail.MailAddress("jane@contoso5.com", "Jane Clayton5"))) $mailMessage.SubjectEncoding = [System.Text.Encoding]::UTF8 $mailMessage.BodyEncoding = [System.Text.Encoding]::UTF8 $mailMessage.Subject = "中文Subject" $mailMessage.IsBodyHtml = $True $mailMessage.Body = "<p>中文mailMessage</p>"
$winDir = New-Object -TypeName "System.Text.Encoding"
New-Object System.Text.Encoding
$smtpClient.Send($mailMessage);
IsBodyHtml
$smtpClient.Send("1643253513@qq.com", "ricardo.qt.lu@pccw.com", "Subject", "mailMessage");
.NET 中的程序集就是 exe 或 dll 程序集通常有一个或多个命名空间
程序集需要先加载再使用 通常会默认加载一部分程序集
jsc csc vbc
windows powershell 依赖 .NET Framework 所以系统里一定有 .NET Framework 有 .NET Framework 也会有 csc jsc vbc 这三个编译器
powershell core 之后有自包含 .NET Framework 的安装包,所以 powershell 可以不依赖 .NET Framework
PowerShell 中只要变量不为 null ,就可以用 Get-Member 方法
在 PowerShell 中,可以通过几种方法判断一个变量是否为 null
。以下是一些常用的方法:
-eq
运算符你可以直接将变量与 $null
进行比较:
if ($variable -eq $null) {
Write-Host "变量是 null"
} else {
Write-Host "变量不是 null"
}
-ne
运算符如果你想检查变量是否不为 null
,可以使用 -ne
运算符:
if ($variable -ne $null) {
Write-Host "变量不是 null"
} else {
Write-Host "变量是 null"
}
if
语句你还可以使用简单的 if
语句来检查变量的存在性:
if ($variable) {
Write-Host "变量不是 null 或空"
} else {
Write-Host "变量是 null 或空"
}
IsNullOrEmpty
方法如果你想同时检查变量是否为 null
或空字符串,可以使用 IsNullOrEmpty
方法:
if ([string]::IsNullOrEmpty($variable)) {
Write-Host "变量是 null 或空字符串"
} else {
Write-Host "变量不是 null 且不是空字符串"
}
这些方法可以帮助你有效地判断 PowerShell 中的变量是否为 null
。选择适合你需求的方法即可。如果你有其他问题或需要进一步的帮助,请告诉我!
-->
[mail function]
; For Win32 only.
; https://php.net/smtp
SMTP = localhost
; https://php.net/smtp-port
smtp_port = 25
;sendmail_from = me@example.com
// 设置收件人地址
$to = 'asd <asd@123.com>, asd2 <asd2@123.com>';
// 设置邮件主题
$subject = 'subject';
// 设置邮件正文
$message = '<p>message</p>';
// 设置邮件头部信息,包括发件人地址和回复地址
$headers = [
'From' => 'Mailer <1643253513@qq.com>',
'Content-Type' => 'text/html; charset=utf-8',
'Reply-To' => 'bing@example.com',
];
$additional_params = '';
// 调用 mail 函数发送邮件
if (mail($to, $subject, $message, $headers, $additional_params)) {
echo "邮件发送成功";
} else {
echo "邮件发送失败";
}
// 理论上是可以在 message 里塞附件的,
// 一些版本的 sendmail 可以在命令行里设置 smtp 地址和账号密码,这时就可以通过 additional_params 变量设置
// mail 函数里的 additional_params 参数可以设置 mta 的更多的命令行参数,
// 其实就类似于这样
// echo "邮件正文" | sendmail -t -i additional_params
// 假设 sendmail 支持 -S -au -ap 三个参数,那么 $additional_params 可以设置成
// $additional_params = ' -S smtp.qq.com:465 -auxxx -apxxxx';
// 那么最后的命令类似于
// echo "邮件正文" | sendmail -t -i -S smtp.qq.com:465 -auxxx -apxxxx
https://github.com/PHPMailer/PHPMailer 6.9
//Import PHPMailer classes into the global namespace
//These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
//Load Composer's autoloader
require 'vendor/autoload.php';
//Create an instance; passing `true` enables exceptions
$mail = new PHPMailer(true);
try {
//Server settings
$mail->SMTPDebug = SMTP::DEBUG_LOWLEVEL; //Enable verbose debug output
$mail->isSMTP(); //Send using SMTP
$mail->Host = 'smtp.qq.com'; //Set the SMTP server to send through
$mail->SMTPAuth = true; //Enable SMTP authentication
$mail->Username = 'joe@example.net'; //SMTP username
$mail->Password = 'matthew'; //SMTP password
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption
$mail->Port = 465; //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
//Recipients
$mail->setFrom('joe@example.net', 'Mailer');
// $mail->addAddress('joe@example.net', 'Joe User'); //Add a recipient
$mail->addAddress('info@example.com'); //Name is optional
// $mail->addReplyTo('info@example.com', 'Information');
// $mail->addCC('cc@example.com');
// $mail->addBCC('bcc@example.com');
//Attachments
// $mail->addAttachment('/var/tmp/file.tar.gz'); //Add attachments
// $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); //Optional name
//Content
$mail->isHTML(true); //Set email format to HTML
$mail->Subject = 'Here is the subject';
$mail->Body = 'This is the HTML message body <b>in bold!</b>';
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
$mail->send();
echo 'Message has been sent';
} catch (Exception $e) {
echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
https://github.com/symfony/mailer 6.4
require './vendor/autoload.php';
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;
$transport = Transport::fromDsn('smtp://localhost');
$mailer = new Mailer($transport);
$email = (new Email())
->from('hello@example.com')
->to('you@example.com')
//->cc('cc@example.com')
//->bcc('bcc@example.com')
//->replyTo('fabien@example.com')
//->priority(Email::PRIORITY_HIGH)
->subject('Time for Symfony Mailer!')
->text('Sending emails is fun again!')
->html('<p>See Twig integration for better HTML integration!</p>');
$mailer->send($email);
require './vendor/autoload.php';
use Laminas\Mail\Message;
$message = new Message();
$message->addFrom('matthew@example.org', 'Matthew Somelli');
$message->addTo('foobar@example.com', 'foobar');
$message->addTo('foobar2@example.com', 'foobar2');
$message->addCc('ralph@example.org', 'ralph');
$message->addCc('ralph2@example.org', 'ralph2');
$message->addBcc('enrico@example.org', 'enrico');
$message->addBcc('enrico2@example.org', 'enrico2');
$message->addReplyTo('matthew@example.com', 'Matthew');
$message->setSender('matthew@example.org', 'Matthew Sommeli');
$message->setSubject('Sending an email from Laminas\Mail!');
// $message->setEncoding('UTF-8');
$message->setBody('This is the message body.');
// echo $message->toString(); // 这样可以生成一个 IMF 字符串,
$transport = new \Laminas\Mail\Transport\Smtp();
$options = new \Laminas\Mail\Transport\SmtpOptions([
'name' => 'localhost',
'host' => '127.0.0.1',
// 'connection_class' => 'login',
'connection_class' => 'plain',
'connection_config' => [
'username' => 'user',
'password' => 'pass',
],
]);
$transport->setOptions($options);
$transport->send($message);
https://github.com/zetacomponents/Mail 1.9
安装命令
composer require zetacomponents/mail
这个库和其它的不一样,没有命名空间
require __DIR__ . '/vendor/autoload.php';
// 配置参数(根据实际情况修改)
$smtpHost = 'localhost'; // SMTP服务器地址
$smtpPort = 25; // 端口
$smtpUsername = 'user@example.com'; // 发件邮箱
$smtpPassword = 'your-password'; // 邮箱密码或应用专用密码
$fromEmail = 'sender@example.com'; // 发件人地址
$fromName = '系统发件人'; // 发件人名称
$toEmail = 'recipient@example.com';// 收件人地址
$toName = '收件人名称'; // 收件人名称
// 创建邮件对象
$mail = new ezcMail();
$mail->from = new ezcMailAddress($fromEmail, $fromName);
$mail->addTo(new ezcMailAddress($toEmail, $toName));
$mail->subject = '来自 Composer 示例的测试邮件';
// 发送纯文本
// $mail->body = new ezcMailText("这是一封通过 zetacomponents/mail 和 Composer 发送的邮件。", 'utf-8');
// 发送html
$textPart = new ezcMailText("<h1>这是一封通过 zetacomponents/mail 和 Composer 发送的邮件。</h1>", 'utf-8');
$textPart->subType = 'html';
$mail->body = $textPart;
// 配置 SMTP 传输
$options = new ezcMailSmtpTransportOptions();
// $options->connectionType = ezcMailSmtpTransport::CONNECTION_TLS; // 使用 TLS 加密
$transport = new ezcMailSmtpTransport(
$smtpHost,
$smtpUsername,
$smtpPassword,
$smtpPort,
$options
);
// 发送邮件
try {
$transport->send($mail);
echo "邮件已成功发送至 {$toEmail}";
} catch (Exception $e) {
echo "发送失败: " . $e->getMessage();
}
<!--
## python 发送邮件
https://docs.python.org/zh-cn/3.13/library/smtplib.html
https://docs.python.org/zh-cn/3.13/library/email.html
https://docs.python.org/zh-cn/3.13/library/email.examples.html
-->roundcube-framework-1.6.10.tar.gz roundcubemail-1.6.10-complete.tar.gz roundcubemail-1.6.10.tar.gz <!--
docker run --name emailsystem --rm -it -p 8080:8080 php:8.1-bullseye /bin/bash
cp /etc/apt/sources.list /etc/apt/sources.list_bak && \ sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \ apt update && \ apt install -y vim && \ apt install -y curl && \ apt install -y net-tools && \ apt install -y netcat && \ apt install -y procps && \ apt install -y dnsutils && \ apt install -y mailutils && \ apt install -y postfix && \ apt install -y bzip2 && \ apt install -y make && \ apt install -y gcc && \ apt install -y git && \ cd && \ curl -O "https://busybox.net/downloads/busybox-1.36.1.tar.bz2" && \ tar -xjf ./busybox-1.36.1.tar.bz2 && \ cd busybox-1.36.1 && \ make defconfig && \ make install && \ cp /root/busybox-1.36.1/busybox /bin/busybox && \ cd
curl -sS -o composer.phar https://getcomposer.org/composer.phar && \ chmod 0755 composer.phar && \ mv composer.phar /usr/local/bin/composer
cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini
apt install -y libzip-dev unzip && \ docker-php-ext-install zip
apt install -y libicu-dev && \ docker-php-ext-install intl
docker-php-ext-install exif
apt install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libjpeg-dev \ libpng-dev \ libwebp-dev && \ docker-php-ext-configure gd --with-jpeg --with-freetype && \ docker-php-ext-install gd
docker-php-ext-install opcache
curl -L -o roundcubemail.tar.gz --connect-timeout 120 --max-time 3600 --retry 100 --retry-delay 5 https://github.com/roundcube/roundcubemail/releases/download/1.6.10/roundcubemail-1.6.10-complete.tar.gz
tar -zxf roundcubemail.tar.gz
cd roundcubemail-1.6.10
cp composer.json composer.json-bak cp composer.json-dist composer.json
composer update
PHP_CLI_SERVER_WORKERS="10" php -S 127.0.0.1:8080 PHP_CLI_SERVER_WORKERS="10" php -S 0.0.0.0:8080
https://8080-cs-285386365050-default.cs-asia-east1-jnrc.cloudshell.dev/installer/index.php
touch roundcubemail.sqlite
cat config/config.inc.php vi config/config.inc.php
sqlite:///roundcubemail.sqlite
chmod 777 roundcubemail.sqlite
-->