SMTP C++;linux使用套接字如何实现SSL? 我在Linux套接字中有C++的SMTP.CPP程序的问题。 我必须输入以下(域)account@domain recipient@domain附件和准备邮件),填写后,smtp应发送电子邮件至 recipient@domain但它一直在说信息没有被发送。 smtp没有ssl,因为我只想使用port25发送电子邮件和测试。 但是我不能在端口25上使用它,我需要在套接字上实现SSL(端口465)。有人知道如何实现这一点,以便smtp工作吗? 请帮忙
smtp.cppSMTP C++;linux使用套接字如何实现SSL? 我在Linux套接字中有C++的SMTP.CPP程序的问题。 我必须输入以下(域)account@domain recipient@domain附件和准备邮件),填写后,smtp应发送电子邮件至 recipient@domain但它一直在说信息没有被发送。 smtp没有ssl,因为我只想使用port25发送电子邮件和测试。 但是我不能在端口25上使用它,我需要在套接字上实现SSL(端口465)。有人知道如何实现这一点,以便smtp工作吗? 请帮忙,c++,linux,sockets,smtp,C++,Linux,Sockets,Smtp,smtp.cpp #include <cstdio> #include <cstdlib> #include <cstring> #include <set> #include <string> #include <iostream> #include <ctime> #include <fstream> #include <errno.h> #include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
#include <string>
#include <iostream>
#include <ctime>
#include <fstream>
#include <errno.h>
#include <netdb.h>//s_port , h_name,h_addrtype
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sstream>
#include <vector>
using namespace std;
#define buf_size 1024
#define chunk_size 54 //rozmiar porcji
void err(const char *where)
{
fprintf(stderr, "error in %s: %d\n", where, errno);
exit(1);
}
string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string BOUNDARY_TEXT = "BOUNDARY_TEXT";
string CRLF = "\r\n";//CR, wartość ASCII równa 13, '\r') + line feed (LF, wartość ASCII 10, '\n'
// OZNACZA koniec bieżącej linii
string getFormatTime()
{
time_t rawtime;
struct tm * timeinfo;
char bufer[80];
time (&rawtime);
timeinfo = localtime (&rawtime);
strftime (bufer, 80, "Date: %a, %d %B %Y %T %z", timeinfo);//Format time as string
string time(bufer);
return time;
}
string getHeader(string login, string recipient, string subject, vector<string> &attachments)
{
stringstream header;
// Date: <SP> <dd> <SP> <mon> <SP> <yy> <SP> <hh> ":" <mm> ":" <ss> <SP> <zone> <CRLF>
header << getFormatTime() << CRLF;
// From: <SP> <sender> <SP> "<" <sender-email> ">" <CRLF>
header << "From: <" << login << ">" << CRLF;
// X-Mailer: <SP> <xmailer-app> <CRLF>
header << "X-Mailer: Poster" << CRLF;
// Reply-To: <SP> <reverse-path> <CRLF>
// X-Priority: <SP> <number> <CRLF>
header << "X-Priority: 3 (Normal)" << CRLF;
// To: <SP> <remote-user-mail> <CRLF>
header << "To: <" << recipient << ">" << CRLF;
// Cc: <SP> <remote-user-mail> <CRLF>
// Bcc: <SP> <remote-user-mail> <CRLF>
// Subject: <SP> <subject-text> <CRLF>
header << "Subject: " << subject << CRLF;
// MIME-Version: <SP> 1.0 <CRLF>
header << "MIME-Version: 1.0" << CRLF;
if(attachments.size() == 0)
{
//Content-Type POLE TYPU ZAWARTOŚCI
// uzywane jest do wskazania klientowi poczty zarówno uzytego sposobu kodowania
//wiadomosci, jak i ewentualnie sposobu postepowania z odebrana wiadomoscia.
header << "Content-type: text/plain; charset=US-ASCII" << CRLF;
//Content-Transfer-Encoding informuje, w jaki sposob traktuje sie znaki o kodach wiekszych od 127
header << "Content-Transfer-Encoding: 7bit" << CRLF;
header << CRLF;
}
else
{
//wiadomosc zawiera kilka rozlacznych czesci
//Tekst w 'boundary' bedzie wykorzystywany jako znacznik rozdzielajacy kazdy ze skladnikow wiadomosci
header << "Content-Type: multipart/mixed; boundary=\"";
header << BOUNDARY_TEXT << "\"" << CRLF;
header << "--" << BOUNDARY_TEXT << CRLF;
header << "Content-type: text/plain; charset=US-ASCII" << CRLF;
header << "Content-Transfer-Encoding: 7bit" << CRLF;
header << CRLF;
}
return header.str();
}
//kodowanie wiadomosci
string encode(char* chunk, int length)
{
string ostr = "";
static long long out_size = 0;
for(int i = 0; i < length; i+=3)
{
unsigned char s1 = chunk[i];
//Gott!!! FIXED
unsigned char s2 = (length > 1) ? chunk[i+1] : 0;
unsigned char s3 = (length > 2) ? chunk[i+2] : 0;
int n = s1;
n <<= 8;
n |= s2;
n <<= 8;
n |= s3;
int p1 = static_cast<int>(n & 0x3f);
n >>= 6;
int p2 = static_cast<int>(n & 0x3f);
n >>= 6;
int p3 = static_cast<int>(n & 0x3f);
n >>= 6;
int p4 = static_cast<int>(n & 0x3f);
ostr += base64_chars[p4];
ostr += base64_chars[p3];
if(length - i >= 3)
{
ostr += base64_chars[p2];
ostr += base64_chars[p1];
}
if(length - i == 2)
{
ostr += base64_chars[p2];
ostr += '=';
}
if(length - i == 1)
{
ostr += '=';
ostr += '=';
}
out_size += 4;
}
return ostr;
}
/*
Funkcja getline jest preferowana metoda czytania linii tekstu z gniazda,
w tym standardowych wejscia.Pobiera linie danych z gniazda socket
*/
static int getLine (int socket, char *line, int length)
{
//memset(line, '\0', buf_size);
char ch;
int bytes = 0;
while (read(socket, &ch, 1) > 0)
{
*line++ = ch;
bytes++;
if (ch == '\n')
{
*line = 0;
return bytes;
}
if (bytes == length - 1)
{
*line = 0;
return bytes;
}
}
*line = 0;
err("problem");
return -1;
}
//wysylanie
void send(int sock, string command)
{
write(sock, command.c_str(), command.length());
}
//odbior
int receive(int sock)
{
char buf[buf_size];
char code[3];
getLine(sock, buf, buf_size);
strncpy(code, buf, 3);
puts(buf);
return atoi(code);;//Convert string to integer
}
//wysyla plik
void sendFile(int sock, string file_to_send)
{
//ifstream - Stream class to read from files
//Construct object and optionally open file
ifstream is(file_to_send.c_str(), ifstream::binary);
string out = "";
if (is)
{
is.seekg(0, is.end);//Set position in input sequence
is.seekg(0, is.beg);
char chunk[chunk_size];
while(!is.eof())
{
is.read(chunk, chunk_size);
send(sock, encode(chunk, is.gcount()) + CRLF);
}
is.close();
}
}
//wysylanie maila
int sendMail(int sock, char* account_login, char* passwd, string recipient, string subject, string msg, vector<string> &attachments)
{
string header;
send(sock, "helo domain" + CRLF);
if(receive(sock) != 250)
err("domain problem");
return -1;
send(sock, "auth login" + CRLF);
if(receive(sock) != 334)
err("auth login problem");
return -2;
//zakodowany login
send(sock, encode(account_login, strlen(account_login)) + CRLF);
if(receive(sock) != 334)
err("encoding login problem");
return -3;
send(sock, encode(passwd, strlen(passwd)) + CRLF);
if(receive(sock) != 235)
err("encoding password problem");
return -4;
string login(account_login);
send(sock, "mail from:" + login + CRLF);
if(receive(sock) != 250)
err("account-domain problem");
return -5;
send(sock, "rcpt to:" + recipient + CRLF);
if(receive(sock) != 250)
err("recipient problem");
return -6;
send(sock, "data" + CRLF);
if(receive(sock) != 354)
err("data problem");
return -7;
header = getHeader(login, recipient, subject, attachments);
send(sock, header);
if(msg.size() == 0)
send(sock, " " + CRLF);
else
send(sock, msg + CRLF);
vector<string>::iterator temp = attachments.begin();
while(++temp != attachments.end())
{
stringstream ss;
ss << "--" << BOUNDARY_TEXT <<
ss << "Content-Type: application/x-msdownload; name=\"";
ss << basename(static_cast<string>(*temp).c_str());
ss << "\"" << CRLF;
//sposob kodowania informacji binarnej
ss << "Content-Transfer-Encoding: base64" << CRLF;
//pole Content-Disposition identyfikuje te czesc wiadomosci jako załacznik
ss << "Content-Disposition: attachment; filename=\"";
ss << basename(static_cast<string>(*temp).c_str());
ss << "\"" << CRLF;
ss << CRLF;
send(sock, ss.str());
cout << *temp << endl;
sendFile(sock, *temp);
}
if(attachments.size() > 0)
{
send(sock, CRLF);
send(sock, "--" + BOUNDARY_TEXT + "--" + CRLF);
}
//Klient musi poprawnie obsługiwać pojawienie się linii wiadomości
//zaczynającej się od kropki lub kropek.
// <CRLF> . <CRLF>
send(sock, CRLF + "." + CRLF);
if(receive(sock) != 250)
err(". problem");
return -8;
send(sock, "quit" + CRLF);
if(receive(sock) != 250)
err("quit problem");
return -9;
return 0;
}
/*
void err(const char *where)
{
fprintf(stderr, "error in %s: %d\n", where, errno);
exit(1);
}
*/
int connect(char* server, const char* proto)
{
//adres serwera np poczta.o2.pl
char *remote = server;
//struktura zwiazana z serwerem
struct servent *sent;
//struktura zwiazana z nazwa protokolu
struct protoent *pent;
int port;
int sock;
int result;
//struct in_addr {in_addr_t s_addr lub ipadr;};
in_addr_t ipadr;
//struktura obslugujaca adresowe internetowe
struct sockaddr_in addr;
//struktura zwiazana z nazwa hosta
struct hostent *hent;
char buf[buf_size];
char filename[30];
//łańcuch zawierający nazwę usługi (np. ”pop3”,"http" itp)
//łańcuch zawierający nazwę protokołu (”tcp”, ”udp”, ”ip”)
sent = getservbyname(proto, "tcp");
if(sent == NULL)
err("getservbyname");
port = sent->s_port;
pent = getprotobyname("tcp");
if(pent == NULL)
err("getprotobyname");
//nazwa hosta w postaci łańcucha (symboliczna lub adres IP)
hent = gethostbyname(remote);
printf("Host: %s\n", hent->h_name);
printf("IP: %s\n", inet_ntoa(*((struct in_addr *)hent->h_addr)));
//struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr = *((struct in_addr *)hent->h_addr);
//Sets the first 8 bytes of the block of memory pointed by sin_zero to the specified value \0
memset(addr.sin_zero, '\0', 8);
//AF_INET - internet domain sockets|SOCK_STREAM - Byte-stream socket,
sock = socket(AF_INET, SOCK_STREAM, pent->p_proto);
if(sock < 0)
err("socket");
result = connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));
if(result < 0)
err("connect");
getLine(sock, buf, buf_size);
puts(buf);
return sock;
}
int main(int argc, char* argv[])
{
if(argc < 4)
{
cout << "usage: " << argv[0] << ": domain account@domain recipient@domain [attachment, attachment, ...]" << endl;
return 0;
}
char* server = argv[1];
char* account_login = argv[2];
string recipient(argv[3]);
string subject = "";
string msg = "";
vector<string> attachments;
for(int i = 3; i < argc; i++)
{
string filename(argv[i]);
attachments.push_back(filename);
}
cout << "Preparing message..." << endl << endl;
cout << "Enter your topic: " << endl;
getline(cin, subject);
cout << "Enter your message here <EOF>" << endl;
char tempChar;
while (!cin.eof())
{
cin.get(tempChar);
msg += tempChar;
}
//getpass - ukrywa nam haslo podczas wprowadzania go na ekranie
char* passwd = (char*)(intptr_t)getpass("Enter password: ");
int sock = connect(server, "smtp");
if(sendMail(sock, account_login, passwd, recipient, subject, msg, attachments) != 0)
cout`enter code here` << "Message not sent." << endl;
else
cout << "Message has been sent successfully." << endl;
close(sock);
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括//s\U端口、h\U名称、h\U地址类型
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
#定义buf_大小1024
#定义块大小54//rozmiar porcji
无效错误(常量字符*其中)
{
fprintf(标准,“%s中的错误:%d\n”,其中,errno);
出口(1);
}
字符串base64_chars=“abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyzo123456789+/”;
字符串BOUNDARY\u TEXT=“BOUNDARY\u TEXT”;
字符串CRLF=“\r\n”//CR,wartośćASCII równa 13,'\r')+换行符(LF,wartośćASCII 10,'\n'
//奥兹纳扎·科尼奇·比埃切伊·利尼
字符串getFormatTime()
{
时间与时间;
结构tm*时间信息;
char-bufer[80];
时间(&rawtime);
timeinfo=localtime(&rawtime);
strftime(bufer,80,“日期:%a,%d%B%Y%T%z”,timeinfo);//将时间格式化为字符串
字符串时间(bufer);
返回时间;
}
string getHeader(字符串登录、字符串收件人、字符串主题、向量和附件)
{
串流头;
//日期::“”
头允许sendMail()
为几十个不同的错误返回相同的错误代码,并且根本不打印任何错误消息,这对调试非常没有帮助。修复sendMail()
相应地。之后,您将知道它在哪里中断以及可能中断的原因。类似的问题也适用于您的其他函数。在很多地方,您只需忽略返回代码。也可以解决此问题。查看errno
将有助于../smtp poczta.o2.plkalamata1991@o2.pl erotas@amorki.pllol.txt正在准备消息…E输入你的主题:fgffg在这里输入你的消息gfgfgf ssfs输入密码:Host:poczta.o2.pl IP:193.17.41.99 220 poczta.o2.pl ESMTP Wita 250 poczta.o2.pl域错误问题:0我肯定写了正确的域。我不知道为什么会出现错误使用像…这样的库并使用g++-Wall-g
编译,然后使用调试器(gdb
)我只能使用套接字提供的库和类。我不能使用其他库或类,因为错误发生在receive()
?在这种情况下,请检查服务器返回了什么(可能是错误消息?)以及发生了什么错误代码。此外,我不会调用getline()
在套接字上,使用read()
并检查其返回代码。