1 (изменено: Malcev, 2021-05-12 00:58:34)

Тема: AHK: Отправка почты через соккеты, TLS и Schannel

Попробовал отправить почту через соккеты с помощью Secure Channel API.
Хорошая статья по теме:
https://sites.google.com/site/libfcgi2/ … h-schannel

server := "smtp.gmail.com"
port := 465   ; can be 587
login := "YourEmail@gmail.com"
password := "YourPassword"
MailTo := "MailTo@gmail.com"
Subject := "Test from Malcev"
EmailText := "This is a test message"

Base64 := Base64(login, password)
data = 
(
EHLO Malcev \r\n
AUTH PLAIN %Base64% \r\n
MAIL FROM:<%login%> \r\n
RCPT TO:<%MailTo%> \r\n
DATA \r\n
Subject: %Subject% \r\n\r\n %EmailText% \r\n.\r\n
QUIT \r\n
)

dwSSPIFlags := (ISC_REQ_SEQUENCE_DETECT := 8) | (ISC_REQ_REPLAY_DETECT := 4) | (ISC_REQ_CONFIDENTIALITY := 16) | (ISC_RET_EXTENDED_ERROR := 16384) | (ISC_REQ_ALLOCATE_MEMORY := 256) | (ISC_REQ_STREAM := 32768)
SEC_E_OK := 0
SEC_I_CONTINUE_NEEDED := 0x00090312
SEC_E_INCOMPLETE_MESSAGE := 0x80090318
SEC_I_INCOMPLETE_CREDENTIALS := 0x00090320
SEC_I_CONTEXT_EXPIRED := 0x00090317
SEC_I_RENEGOTIATE := 0x00090321
SECBUFFER_DATA := 1
SECBUFFER_TOKEN := 2
SECBUFFER_EXTRA := 5
SECBUFFER_STREAM_TRAILER := 6
SECBUFFER_STREAM_HEADER := 7
IO_BUFFER_SIZE := 65536

DllCall("LoadLibrary", "str", "ws2_32.dll", "ptr")
VarSetCapacity(WSADATA, 394 + (A_PtrSize - 2) + A_PtrSize, 0)
DllCall("ws2_32\WSAStartup", "ushort", 0x0202, "ptr", &WSADATA)
socket := DllCall("ws2_32\socket", "int", PF_INET := 2, "int", SOCK_STREAM := 1, "int", 0)
sin_port := DllCall("ws2_32\htons", "ushort", port, "ushort")
VarSetCapacity(addrinfo, 16+4*A_PtrSize, 0)
NumPut(AF_INET := 2, addrinfo, 4, "int")
NumPut(SOCK_STREAM := 1, addrinfo, 8, "int")
NumPut(IPPROTO_TCP := 6, addrinfo, 12, "int")
DllCall("ws2_32\getaddrinfo", "astr", server, "ptr", 0, "ptr", &addrinfo, "ptr*", addrinfoOut)
addrinfoOut_ai_addr := NumGet(addrinfoOut+0, 16+2*A_PtrSize, "ptr")
sin_addr := NumGet(addrinfoOut_ai_addr+0, 4, "uint")
VarSetCapacity(sockaddr_in, 16, 0)
NumPut(AF_INET := 2, sockaddr_in, 0, "short")   ; sin_family
NumPut(sin_port, sockaddr_in, 2, "ushort")   ; sin_port
NumPut(sin_addr, sockaddr_in, 4, "uint")   ; sin_addr
DllCall("ws2_32\connect", "int", socket, "ptr", &sockaddr_in, "int", 16)
if (port != 465)
{
   ReceivedDataSize := 4096
   VarSetCapacity(ReceivedData, ReceivedDataSize, 0)
   DllCall("ws2_32\recv", "int", socket, "ptr", &ReceivedData, "int", ReceivedDataSize, "int", 0)
   msgbox % strget(&ReceivedData, "utf-8")
   string := "EHLO Malcev`r`n"
   DllCall("ws2_32\send", "int", socket, "astr", string, "int", strlen(string), "int", 0)
   VarSetCapacity(ReceivedData, ReceivedDataSize, 0)
   DllCall("ws2_32\recv", "int", socket, "ptr", &ReceivedData, "int", ReceivedDataSize, "int", 0)
   msgbox % strget(&ReceivedData, "utf-8")
   string := "starttls`r`n"
   DllCall("ws2_32\send", "int", socket, "astr", string, "int", strlen(string), "int", 0)
   VarSetCapacity(ReceivedData, ReceivedDataSize, 0)
   DllCall("ws2_32\recv", "int", socket, "ptr", &ReceivedData, "int", ReceivedDataSize, "int", 0)
   msgbox % strget(&ReceivedData, "utf-8")
}

DllCall("LoadLibrary","str", "Secur32.dll", "ptr")
g_pSSPI := DllCall("Secur32\InitSecurityInterface", "ptr")
VarSetCapacity(hCreds, 2*A_PtrSize, 0)
VarSetCapacity(SchannelCred, A_PtrSize*6+40, 0)
NumPut(SCHANNEL_CRED_VERSION := 4, SchannelCred, 0, "uint")   ; dwVersion
NumPut(SP_PROT_TLS1_2_CLIENT := 0x800, SchannelCred, A_PtrSize*6+16, "uint")   ; grbitEnabledProtocols
NumPut(SCH_CRED_NO_DEFAULT_CREDS := 0x00000010, SchannelCred, A_PtrSize*6+32, "uint")   ; dwFlags
DllCall(NumGet(g_pSSPI+3*A_PtrSize), "ptr", 0, "ptr", &(UNISP_NAME := "Microsoft Unified Security Protocol Provider"), "uint", SECPKG_CRED_OUTBOUND := 0x2, "ptr", 0, "ptr", &SchannelCred, "ptr", 0, "ptr", 0, "ptr", &hCreds, "int64*", tsExpiry)   ; AcquireCredentialsHandle
VarSetCapacity(OutBuffers, 8+A_PtrSize, 0)
NumPut(SECBUFFER_TOKEN, OutBuffers, 4, "uint")   ; BufferType
VarSetCapacity(OutBuffer, 8+A_PtrSize, 0)
NumPut(1, OutBuffer, 4, "uint")   ; cBuffers
NumPut(&OutBuffers, OutBuffer, 8, "ptr")   ; pBuffers
VarSetCapacity(hContext, 2*A_PtrSize, 0)
scRet := DllCall(NumGet(g_pSSPI+6*A_PtrSize), "ptr", &hCreds, "ptr", 0, "ptr", &server, "uint", dwSSPIFlags, "uint", 0, "uint", SECURITY_NATIVE_DREP := 16, "ptr", 0, "uint", 0, "ptr", &hContext, "ptr", &OutBuffer, "uint*", dwSSPIOutFlags, "int64*", tsExpiry, "uint")   ; InitializeSecurityContext
if (scRet != SEC_I_CONTINUE_NEEDED)
{
   msgbox InitializeSecurityContext first time error
   exitapp
}
OutBuffers0_cbBuffer := NumGet(OutBuffers, 0, "uint")
OutBuffers0_pvBuffer := NumGet(OutBuffers, 8, "ptr")
if (OutBuffers0_cbBuffer != 0) and (OutBuffers0_pvBuffer != 0)
{
   cbData := DllCall("ws2_32\send", "int", socket, "ptr", OutBuffers0_pvBuffer, "int", OutBuffers0_cbBuffer, "int", 0)
   if (cbData <= 0)
   {
      msgbox ws2_32\send first time error
      exitapp
   }
   DllCall(NumGet(g_pSSPI+16*A_PtrSize), "ptr", OutBuffers0_pvBuffer)   ; FreeContextBuffer
}
fDoRead := 1
GoSub HandshakeLoop
VarSetCapacity(Sizes, 20, 0)
scRet := DllCall(NumGet(g_pSSPI+11*A_PtrSize), "ptr", &hContext, "uint", SECPKG_ATTR_STREAM_SIZES := 4, "ptr", &Sizes, "uint")   ; QueryContextAttributes
if (scRet != SEC_E_OK)
{
   msgbox QueryContextAttributes error
   exitapp
}
Sizes_cbHeader := NumGet(Sizes, 0, "uint")
Sizes_cbTrailer := NumGet(Sizes, 4, "uint")
Sizes_cbMaximumMessage := NumGet(Sizes, 8, "uint")
cbIoBufferLength := Sizes_cbHeader + Sizes_cbMaximumMessage + Sizes_cbTrailer
VarSetCapacity(pbIoBuffer, cbIoBufferLength, 0)
if (port = 465)
   GoSub ReadDecrypt
Loop, parse, data, `n, `r
{
   sendData := StrReplace(A_LoopField, "\r\n", "`r`n")
   GoSub EncryptSend
   msgbox % DecryptedData
}

;DisconnectFromServer
VarSetCapacity(SCHANNEL_SHUTDOWN, 4, 0)
NumPut(1, SCHANNEL_SHUTDOWN, 0, "int")
VarSetCapacity(OutBuffers, 8+A_PtrSize, 0)
NumPut(4, OutBuffers, 0, "uint")   ; cbBuffer
NumPut(SECBUFFER_TOKEN, OutBuffers, 4, "uint")   ; BufferType
NumPut(&SCHANNEL_SHUTDOWN, OutBuffers, 8, "ptr")   ; pbBuffer
VarSetCapacity(OutBuffer, 8+A_PtrSize, 0)
NumPut(1, OutBuffer, 4, "uint")   ; cBuffers
NumPut(&OutBuffers, OutBuffer, 8, "ptr")   ; pBuffers
scRet := DllCall(NumGet(g_pSSPI+10*A_PtrSize), "ptr", &hContext, "ptr", &OutBuffer, "uint")   ; ApplyControlToken
if (scRet != SEC_E_OK)
{
   msgbox ApplyControlToken error
   exitapp
}
VarSetCapacity(OutBuffers, 8+A_PtrSize, 0)
NumPut(SECBUFFER_TOKEN, OutBuffers, 4, "uint")   ; BufferType
VarSetCapacity(OutBuffer, 8+A_PtrSize, 0)
NumPut(1, OutBuffer, 4, "uint")   ; cBuffers
NumPut(&OutBuffers, OutBuffer, 8, "ptr")   ; pBuffers
scRet := DllCall(NumGet(g_pSSPI+6*A_PtrSize), "ptr", &hCreds, "ptr", &hContext, "ptr", 0, "uint", dwSSPIFlags, "uint", 0, "uint", SECURITY_NATIVE_DREP := 16, "ptr", 0, "uint", 0, "ptr", &hContext, "ptr", &OutBuffer, "uint*", dwSSPIOutFlags, "int64*", tsExpiry, "uint")   ; InitializeSecurityContext
if (scRet >= 0x80000000)
{
   msgbox InitializeSecurityContext disconnect error
   exitapp
}
OutBuffers0_cbBuffer := NumGet(OutBuffers, 0, "uint")
OutBuffers0_pvBuffer := NumGet(OutBuffers, 8, "ptr")
if (OutBuffers0_cbBuffer != 0) and (OutBuffers0_pvBuffer != 0)
{
   cbData := DllCall("ws2_32\send", "int", socket, "ptr", OutBuffers0_pvBuffer, "int", OutBuffers0_cbBuffer, "int", 0)
   if (cbData <= 0)
   {
      msgbox ws2_32\send close notify error
      exitapp
   }
   DllCall(NumGet(g_pSSPI+16*A_PtrSize), "ptr", OutBuffers0_pvBuffer)   ; FreeContextBuffer
}
scRet := DllCall(NumGet(g_pSSPI+9*A_PtrSize), "ptr", &hContext, "uint")   ; DeleteSecurityContext
if (scRet != SEC_E_OK)
{
   msgbox DeleteSecurityContext error
   exitapp
}
cbData := DllCall("Ws2_32\closesocket", "int", socket)
if (cbData != 0)
{
   msgbox closesocket error
   exitapp
}
DllCall("ws2_32\WSACleanup")
msgbox done
ExitApp


HandshakeLoop:
VarSetCapacity(IoBuffer, IO_BUFFER_SIZE, 0)
cbIoBuffer := 0
scRet := SEC_I_CONTINUE_NEEDED
loop
{
   if (scRet = SEC_I_CONTINUE_NEEDED) or (scRet = SEC_E_INCOMPLETE_MESSAGE) or (scRet = SEC_I_INCOMPLETE_CREDENTIALS)
   {
      if (cbIoBuffer = 0) or (scRet = SEC_E_INCOMPLETE_MESSAGE)
      {
         if fDoRead
         {
            cbData := DllCall("ws2_32\recv", "int", socket, "ptr", &IoBuffer+cbIoBuffer, "int", IO_BUFFER_SIZE-cbIoBuffer, "int", 0)
            if (cbData = -1)
            {
                msgbox SOCKET_ERROR
                exitapp
            }
            else if (cbData = 0)
            {
                msgbox SEC_E_INTERNAL_ERROR
                exitapp
            }
            cbIoBuffer += cbData
         }
         else
            fDoRead := 1
      }
      VarSetCapacity(InBuffers, (8+A_PtrSize)*2, 0)
      NumPut(cbIoBuffer, InBuffers, 0, "uint")   ; cbBuffer
      NumPut(SECBUFFER_TOKEN, InBuffers, 4, "uint")   ; BufferType
      NumPut(&IoBuffer, InBuffers, 8, "ptr")   ; pbBuffer
      VarSetCapacity(InBuffer, 8+A_PtrSize, 0)
      NumPut(2, InBuffer, 4, "uint")   ; cBuffers
      NumPut(&InBuffers, InBuffer, 8, "ptr")   ; pBuffers
      VarSetCapacity(OutBuffers, 8+A_PtrSize, 0)
      NumPut(SECBUFFER_TOKEN, OutBuffers, 4, "uint")   ; BufferType
      VarSetCapacity(OutBuffer, 8+A_PtrSize, 0)
      NumPut(1, OutBuffer, 4, "uint")   ; cBuffers
      NumPut(&OutBuffers, OutBuffer, 8, "ptr")   ; pBuffers
      scRet := DllCall(NumGet(g_pSSPI+6*A_PtrSize), "ptr", &hCreds, "ptr", &hContext, "ptr", 0, "uint", dwSSPIFlags, "uint", 0, "uint", SECURITY_NATIVE_DREP := 16, "ptr", &InBuffer, "uint", 0, "ptr", 0, "ptr", &OutBuffer, "uint*", dwSSPIOutFlags, "int64*", tsExpiry, "uint")   ; InitializeSecurityContext
      if (scRet = SEC_E_OK) or (scRet = SEC_I_CONTINUE_NEEDED) or ((scRet >= 0x80000000) and (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
      {
         OutBuffers0_cbBuffer := NumGet(OutBuffers, 0, "uint")
         OutBuffers0_pvBuffer := NumGet(OutBuffers, 8, "ptr")
         if (OutBuffers0_cbBuffer != 0) and (OutBuffers0_pvBuffer != 0)
         {
            cbData := DllCall("ws2_32\send", "int", socket, "ptr", OutBuffers0_pvBuffer, "int", OutBuffers0_cbBuffer, "int", 0)
            if (cbData <= 0)
            {
               msgbox ws2_32\send loop error
               exitapp
            }
            DllCall(NumGet(g_pSSPI+16*A_PtrSize), "ptr", OutBuffers0_pvBuffer)   ; FreeContextBuffer
         }
      }
      if (scRet = SEC_E_INCOMPLETE_MESSAGE)
         Continue
      if (scRet = SEC_E_OK)
         break
      if (scRet >= 0x80000000) and (scRet != SEC_I_CONTINUE_NEEDED)
      {
         msgbox InitializeSecurityContext loop error
         exitapp
      }
      if (scRet = SEC_I_INCOMPLETE_CREDENTIALS)
      {
         msgbox SEC_I_INCOMPLETE_CREDENTIALS error
         exitapp
      }
      InBuffers1_BufferType := NumGet(InBuffers, 8+A_PtrSize+4, "uint")
      if (InBuffers1_BufferType = SECBUFFER_EXTRA)
      {
         InBuffers1_cbBuffer := NumGet(InBuffers, 8+A_PtrSize, "uint")
         DllCall("RtlMoveMemory", "ptr", &IoBuffer, "ptr", &IoBuffer + cbIoBuffer - InBuffers1_cbBuffer, "ptr", InBuffers1_cbBuffer)
         cbIoBuffer := InBuffers1_cbBuffer
      }
      else
         cbIoBuffer := 0
   }
}
return

EncryptSend:
pbMessage := &pbIoBuffer+Sizes_cbHeader
cbMessage := StrLen(sendData)
StrPut(sendData, pbMessage, cbMessage, "UTF-8")
VarSetCapacity(Buffers, (8+A_PtrSize)*4, 0)
NumPut(Sizes_cbHeader, Buffers, (8+A_PtrSize)*0, "uint")   ; cbBuffer
NumPut(SECBUFFER_STREAM_HEADER, Buffers, (8+A_PtrSize)*0 + 4, "uint")   ; BufferType
NumPut(&pbIoBuffer, Buffers, (8+A_PtrSize)*0 + 8, "ptr")   ; pbBuffer
NumPut(cbMessage, Buffers, (8+A_PtrSize)*1, "uint")   ; cbBuffer
NumPut(SECBUFFER_DATA, Buffers, (8+A_PtrSize)*1 + 4, "uint")   ; BufferType
NumPut(pbMessage, Buffers, (8+A_PtrSize)*1 + 8, "ptr")   ; pbBuffer
NumPut(Sizes_cbTrailer, Buffers, (8+A_PtrSize)*2, "uint")   ; cbBuffer
NumPut(SECBUFFER_STREAM_TRAILER, Buffers, (8+A_PtrSize)*2 + 4, "uint")   ; BufferType
NumPut(pbMessage + cbMessage, Buffers, (8+A_PtrSize)*2 + 8, "ptr")   ; pbBuffer
VarSetCapacity(Message, 8+A_PtrSize, 0)
NumPut(4, Message, 4, "uint")   ; cBuffers
NumPut(&Buffers, Message, 8, "ptr")   ; pBuffers
scRet := DllCall(NumGet(g_pSSPI+25*A_PtrSize), "ptr", &hContext, "uint", 0, "ptr", &Message, "uint")   ; EncryptMessage
if (scRet != SEC_E_OK)
{
   msgbox EncryptMessage error
   exitapp
}
cbData := DllCall("ws2_32\send", "int", socket, "ptr", &pbIoBuffer, "int", Sizes_cbHeader + cbMessage + Sizes_cbTrailer, "int", 0)
if (cbData <= 0)
{
   msgbox ws2_32\send EncryptMessage error
   exitapp
}

ReadDecrypt:
DecryptedData := ""
cbIoBuffer := scRet := 0
loop
{
   if (cbIoBuffer = 0) or (scRet = SEC_E_INCOMPLETE_MESSAGE)
   {
      cbData := DllCall("ws2_32\recv", "int", socket, "ptr", &pbIoBuffer+cbIoBuffer, "int", cbIoBufferLength-cbIoBuffer, "int", 0)
      if (cbData = -1)
      {
          msgbox SOCKET_ERROR
          exitapp
      }
      else if (cbData = 0)
      {
         if cbIoBuffer
         {
            msgbox SEC_E_INTERNAL_ERROR
            exitapp
         }
         else
            break
      }
      else
         cbIoBuffer += cbData
   }
   VarSetCapacity(Buffers, (8+A_PtrSize)*4, 0)
   NumPut(cbIoBuffer, Buffers, 0, "uint")   ; cbBuffer
   NumPut(SECBUFFER_DATA, Buffers, 4, "uint")   ; BufferType
   NumPut(&pbIoBuffer, Buffers, 8, "ptr")   ; pbBuffer
   VarSetCapacity(Message, 8+A_PtrSize, 0)
   NumPut(4, Message, 4, "uint")   ; cBuffers
   NumPut(&Buffers, Message, 8, "ptr")   ; pBuffers
   scRet := DllCall(NumGet(g_pSSPI+26*A_PtrSize), "ptr", &hContext, "ptr", &Message, "uint", 0, "uint*", 0, "uint")   ; DecryptMessage
   if (scRet = SEC_I_CONTEXT_EXPIRED)
      break
   if (scRet != SEC_E_OK) and (scRet != SEC_I_RENEGOTIATE) and (scRet != SEC_I_CONTEXT_EXPIRED)
   {
      msgbox DecryptMessage error
      exitapp
   }
   pDataBuffer := pExtraBuffer := ""
   loop 4
   {
      Buffers_BufferType := NumGet(Buffers, (A_Index-1)*(8+A_PtrSize) + 4, "uint")
      if (pDataBuffer = "") and (Buffers_BufferType = SECBUFFER_DATA)
         pDataBuffer  := &Buffers + (A_Index-1)*(8+A_PtrSize)
      if (pExtraBuffer = "") and (Buffers_BufferType = SECBUFFER_EXTRA)
         pExtraBuffer  := &Buffers + (A_Index-1)*(8+A_PtrSize)
   }
   if pDataBuffer
   {
      pDataBuffer_cbBuffer := NumGet(pDataBuffer+0, 0, "uint")
      pDataBuffer_pvBuffer := NumGet(pDataBuffer+0, 8, "ptr")
      DecryptedData := strget(pDataBuffer_pvBuffer, pDataBuffer_cbBuffer, "utf-8")
      if (Substr(DecryptedData, -1) = "`r`n")
         break
   }
   if pExtraBuffer
   {
      pExtraBuffer_cbBuffer := NumGet(pExtraBuffer+0, 0, "uint")
      pExtraBuffer_pvBuffer := NumGet(pExtraBuffer+0, 8, "ptr")
      DllCall("RtlMoveMemory", "ptr", &pbIoBuffer, "ptr", pExtraBuffer_pvBuffer, "ptr", pExtraBuffer_cbBuffer)
      cbIoBuffer := pExtraBuffer_cbBuffer
   }
   else
      cbIoBuffer := 0
   if(scRet = SEC_I_RENEGOTIATE)
   {
      cbIoBufferPrev := cbIoBuffer
      fDoRead := 0
      GoSub HandshakeLoop
      InBuffers1_BufferType := NumGet(InBuffers, 8+A_PtrSize+4, "uint")
      if (InBuffers1_BufferType = SECBUFFER_EXTRA)
      {
         InBuffers1_cbBuffer := NumGet(InBuffers, 8+A_PtrSize, "uint")
         DllCall("RtlMoveMemory", "ptr", &pbIoBuffer, "ptr", &IoBuffer + cbIoBuffer - InBuffers1_cbBuffer, "ptr", InBuffers1_cbBuffer)
         cbIoBuffer := InBuffers1_cbBuffer
      }
      else
         cbIoBuffer := cbIoBufferPrev
   }
}
return

base64(login, password)
{
   VarSetCapacity(bin, StrPut(login, "UTF-8") + StrPut(password, "UTF-8"))
   size := StrPut(login, &bin+1, "UTF-8")
   size += StrPut(password, &bin+1+size, "UTF-8")
   DllCall("crypt32\CryptBinaryToString", "ptr", &bin, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "ptr", 0, "uint*", chars)
   VarSetCapacity(outData, chars << !!A_IsUnicode, 0)
   DllCall("crypt32\CryptBinaryToString", "ptr", &bin, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "str", outData, "uint*", chars)
   return outData
}

2

Re: AHK: Отправка почты через соккеты, TLS и Schannel

У меня выдало DecryptMessage error.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Выдало сразу же после запуска скрипта?
Какой почтовый сервер и какой виндовс?

4

Re: AHK: Отправка почты через соккеты, TLS и Schannel

server "smtp.googlemail.com"
Сначала 220 smtp.googlemail.com ESMTP v12sm3549151ljn.92 - gsmtp
Потом DecryptMessage error
Семёрка.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Значит tls 1.2 в win7 не прописана.
https://www.emailarchitect.net/easendma … 12-2012-r2
А в чем смысл  использовать этого покойника?

6

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Ага, теперь вроде заработало.

Malcev пишет:

А в чем смысл  использовать этого покойника?

Во-первых, чтоб не тратить деньги на новый компьютер, если старый без проблем работает. Во-вторых, мне, как программисту, в любом случае приходится тестировать код на семёрке, так как покойник вполне себе ещё здравствует.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Подправил для наглядности отправки письма.

8

Re: AHK: Отправка почты через соккеты, TLS и Schannel

А WSACleanup здесь не нужно вызывать?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Нужно. Добавил.

10

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Добавил вариант отправки через 25 порт.

11

Re: AHK: Отправка почты через соккеты, TLS и Schannel

А какая разница между этими портами? Я просто в настройках посмотрел, какой у меня.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Тут подробно:
https://habr.com/ru/post/495256/

13

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Ага, примерно понял.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: Отправка почты через соккеты, TLS и Schannel

Добрый день! А не подскажите (server := "smtp.gmail.com" port := 465), адресат определяется как "скрытая копия"


от:	inseption86@gmail.com
Кому:	
скрытая копия:	inseption86@gmail.com,
sidney2000@mail.ru
дата:	10 апр. 2022 г., 11:02
тема:	Test_test
отправлено через:	gmail.com

15

Re: AHK: Отправка почты через соккеты, TLS и Schannel

You do know the difference between headers and envelope headers, right?
If I want to send an email by connecting to a mail server (for instance, through a telnet program), it would look something like this:

$ telnet mail.example.com 25
Trying 127.0.0.42...
Connected to mail.example.com (127.0.0.42).
Escape character is '^]'.
220 mail.example.com ESMTP
HELO mail.example.org
250 mail.example.com
MAIL FROM: <sender@example.org>
250 ok
RCPT TO: <recipient1@example.com>
250 ok
RCPT TO: <recipient2@example.com>
250 ok
RCPT TO: <recipient3@example.com>
250 ok
DATA
354 go ahead
Date: 02 Sep 2011 01:45:59 -0500
Subject: test
From: "Sender" <sender@example.org>
To: "Recipient 1" <recipient1@example.com>
CC: "Recipient 2" <recipient2@example.com>

test
.
250 ok 1314945967 qp 19908
quit
221 mail.example.com
Connection closed by foreign host.

What this means is that BCC recipients are those who appear in the envelope header (RCPT TO lines), whereas TO and CC recipients appear both there and in the DATA section of the email.

This gives you the following email:

Received: (qmail 12019 invoked from network); 2 Sep 2011 01:46:09 
  -0500
Received: from mail.example.org (HELO mail.example.org) (127.0.0.23)
  by mail.example.com with SMTP; 2 Sep 2011 01:46:20 -0500
Received-SPF: pass (mail.example.org: SPF record at example.org 
  designates 127.0.0.23 as permitted sender)
Date: 02 Sep 2011 01:45:59 -0500
Subject: test
From: "Sender" <sender@example.org>
To: "Recipient 1" <recipient1@example.com>
CC: "Recipient 2" <recipient2@example.com>