电子邮件 是最早的互联网应用之一。
一个 电子邮件系统 至少由三部分组成
一封 电子邮件 由两个部分组成
一个 电子邮件地址 由三个部分组成
1*( atext / "." ) "@" ldh-str 1*( "." ldh-str )
/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
总结一下就是 三种协议,一种格式
echo -n "bootstrap@example.com" | base64
echo -n "SendEmails" | base64
AUTH LOGIN
Ym9vdHN0cmFwQGV4YW1wbGUuY29t
U2VuZEVtYWlscw==
\0
printf "\0%s\0%s" "bootstrap@example.com" "SendEmails" | base64
AUTH PLAIN
AGJvb3RzdHJhcEBleGFtcGxlLmNvbQBTZW5kRW1haWxz
\0
,字符串要以 auth 开头 printf "auth\0%s\0%s" "bootstrap@example.com" "SendEmails" | base64
AUTH PLAIN YXV0aABib290c3RyYXBAZXhhbXBsZS5jb20AU2VuZEVtYWlscw==
一个收件人的例子
HELO example.com
AUTH LOGIN
MAIL FROM:<alice@example.com>
RCPT TO:<bob@example.com>
DATA
Date: Mon, 4 April 2022
From: Alice <alice@example.com>
Subject: Eggs benedict casserole
To: Bob <bob@example.com>
Hi Bob,
I will bring the eggs benedict casserole recipe on Friday.
-Alice
.
QUIT
多个个收件人的例子
HELO example.com
AUTH LOGIN
MAIL FROM:<alice@example.com>
RCPT TO:<bob1@example.com>
RCPT TO:<bob2@example.com>
DATA
Date: Mon, 4 April 2022
From: Alice <alice@example.com>
Subject: Eggs benedict casserole
To: Bob <bob@example.com>
Hi Bob,
I will bring the eggs benedict casserole recipe on Friday.
-Alice
.
QUIT
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>';
// 设置邮件头部信息,包括发件人地址和回复地址
$additional_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 参数可以设置 mat 的更多的命令行参数,
// 其实就类似于这样
// echo "邮件正文" | sendmail -t -i additional_params
https://github.com/PHPMailer/PHPMailer
//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}";
}
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);