仓库源文站点原文

电子邮件的不完整总结

电子邮件 是最早的互联网应用之一。

组成

一个 电子邮件系统 至少由三部分组成

一封 电子邮件 由两个部分组成

一个 电子邮件地址 由三个部分组成

总结一下就是 三种协议,一种格式

<!-- ### 客户端 ### 服务端 ## 三种协议,一种格式 ### SMTP ### IMAP ### POP3 ### Internet Message Format -->

如何搭建一个邮件服务器

单机的在不同用户间发送邮件

收发局域网的邮件

收发外网的邮件

加密

<!-- SMTPS 和 STARTTLS 是两种不一样的加密方式 MTA-STS --> ### SPF、DKIM 和 DMARC ### 垃圾邮件 和 病毒 ## 使用命令行发送邮件 ### 交互式命令 - 适用于 nc telnet openssl - 大致分为五个步骤 - 连接到 smtp 服务器 - nc smtp.qq.com 25 - telnet smtp.qq.com 25 - openssl s_client -connect smtp.qq.com:465 - 建立会话; helo - 身份认证; auth login - 理论上不登录也可以的,但除了本地测试的smtp服务器,不会有不需要登录的 - 账号密码需要转换成 base64 - AUTH LOGIN - 输入 AUTH LOGIN 之后,按提示输入,转换成 base64 的账号密码 - 用户转换账号密码的命令,用 echo 输出时要忽略行尾的空格 ``` echo -n "bootstrap@example.com" | base64 echo -n "SendEmails" | base64 ``` - 例子 ``` AUTH LOGIN Ym9vdHN0cmFwQGV4YW1wbGUuY29t U2VuZEVtYWlscw== ``` - AUTH PLAIN 换行 - AUTH PLAIN 之后,在下一行输入,转换成 base64 的账号密码 - 用户转换账号密码的命令,账号和密码前面都有一个 `\0` ``` printf "\0%s\0%s" "bootstrap@example.com" "SendEmails" | base64 ``` - 例子 ``` AUTH PLAIN AGJvb3RzdHJhcEBleGFtcGxlLmNvbQBTZW5kRW1haWxz ``` - AUTH PLAIN 不换行 - 和 AUTH PLAIN 在同一行输入,转换成 base64 的账号密码 - 用户转换账号密码的命令,账号和密码前面都有一个 `\0`,字符串要以 auth 开头 ``` printf "auth\0%s\0%s" "bootstrap@example.com" "SendEmails" | base64 ``` - 例子 ``` AUTH PLAIN YXV0aABib290c3RyYXBAZXhhbXBsZS5jb20AU2VuZEVtYWlscw== ``` - AUTH LOGIN 大多数 smtp 服务器都支持, AUTH PLAIN 换行 这种方式 smtp.qq.com 就不支持了 - 发送邮件信封(发件人和收件人); MAIL FROM 和 RCPT TO - MAIL FROM 只有一个 - RCPT TO 可以有很多个,包含 header 里的 to cc bcc 这些,只需要写地址就可以了,不用写用户名 - 发送邮件内容(邮件正文和附件); 以 DATA 开始 以 . 结束 - 关闭会话; QUIT - 一个收件人的例子 ``` 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: bob1 <bob1@example.com>, bob2 <bob2@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: bob1 <bob1@example.com> Cc: bob2 <bob2@example.com> Hi Bob, I will bring the eggs benedict casserole recipe on Friday. -Alice . QUIT ``` - smtp 命令 NOOP HELP RSET <!-- 可以用 mailpit 作为测试用的服务器 感觉这个位置应该需要一些截图 还需要继续总结一下有哪些 rfc -->

非交互式命令

<!-- curl 用的是第一种方式,所以当前版本的 curl 无法发送邮件到 smtp.qq.com 加上这个参数 --sasl-ir 1 就能使账号密码放在同一行里了 但加上这个参数后,还会再请求一次,而且还是请求失败的那种,可能是我不了解 sasl 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' \ --sasl-ir 1 \ --upload-file mail-curl.txt -->

$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。以下是一些常用的方法:

1. 使用 -eq 运算符

你可以直接将变量与 $null 进行比较:

if ($variable -eq $null) {
    Write-Host "变量是 null"
} else {
    Write-Host "变量不是 null"
}

2. 使用 -ne 运算符

如果你想检查变量是否不为 null,可以使用 -ne 运算符:

if ($variable -ne $null) {
    Write-Host "变量不是 null"
} else {
    Write-Host "变量是 null"
}

3. 简单的 if 语句

你还可以使用简单的 if 语句来检查变量的存在性:

if ($variable) {
    Write-Host "变量不是 null 或空"
} else {
    Write-Host "变量是 null 或空"
}

4. 使用 IsNullOrEmpty 方法

如果你想同时检查变量是否为 null 或空字符串,可以使用 IsNullOrEmpty 方法:

if ([string]::IsNullOrEmpty($variable)) {
    Write-Host "变量是 null 或空字符串"
} else {
    Write-Host "变量不是 null 且不是空字符串"
}

总结

这些方法可以帮助你有效地判断 PowerShell 中的变量是否为 null。选择适合你需求的方法即可。如果你有其他问题或需要进一步的帮助,请告诉我!

-->

php 发送邮件

使用原生的函数

使用第三方库

如何在邮件里显示图片

名词

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

-->