Apply what you learned about sockets to send email from your own program.
| SMTP command | Meaning | Example |
|---|---|---|
HELO | Greeting (announce our hostname) | HELO myhost |
MAIL FROM: | Sender address | MAIL FROM:<sender@example.com> |
RCPT TO: | Recipient address | RCPT TO:<receiver@example.com> |
DATA | Begin the message body | DATA |
. | End the message body | . (a line with only a period) |
QUIT | End the session | QUIT |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/socket.h> #define BUF_SIZE 4096 // send a command and print the server's response void smtp_command(int sock, const char *cmd) { char buf[BUF_SIZE]; if (cmd != NULL) { send(sock, cmd, strlen(cmd), 0); printf("C: %s", cmd); } int n = recv(sock, buf, BUF_SIZE - 1, 0); if (n > 0) { buf[n] = '\0'; printf("S: %s", buf); } } // connect to an SMTP server int connect_smtp(const char *host, int port) { struct hostent *h = gethostbyname(host); if (!h) { fprintf(stderr, "Host lookup failed\n"); return -1; } int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return -1; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); memcpy(&addr.sin_addr.s_addr, h->h_addr, h->h_length); if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("connect"); close(sock); return -1; } return sock; }
int main(void) { const char *smtp_host = "mail.example.com"; const char *from = "alice@example.com"; const char *to = "bob@example.com"; // 1. connect int sock = connect_smtp(smtp_host, 25); if (sock < 0) return 1; // 2. read greeting smtp_command(sock, NULL); // 3. SMTP session smtp_command(sock, "HELO mycomputer\r\n"); char cmd[BUF_SIZE]; snprintf(cmd, BUF_SIZE, "MAIL FROM:<%s>\r\n", from); smtp_command(sock, cmd); snprintf(cmd, BUF_SIZE, "RCPT TO:<%s>\r\n", to); smtp_command(sock, cmd); smtp_command(sock, "DATA\r\n"); // 4. headers and body snprintf(cmd, BUF_SIZE, "Subject: Test from C program\r\n" "From: %s\r\n" "To: %s\r\n" "\r\n" // blank line ends headers "Hello!\r\n" "This mail was sent from a C program.\r\n" ".\r\n", // line with only a period ends the body from, to); smtp_command(sock, cmd); // 5. end session smtp_command(sock, "QUIT\r\n"); close(sock); printf("\nMail sent.\n"); return 0; }
fgets to let the user type the body.// read body from the keyboard printf("Enter mail body (blank line to finish):\n"); char body[BUF_SIZE] = ""; char line[256]; while (1) { fgets(line, 256, stdin); if (line[0] == '\n') break; // blank line to finish strcat(body, line); }
// address book const char *addressbook[] = { "user1@example.com", "user2@example.com", "user3@example.com" }; int num_addr = 3; printf("Select recipient:\n"); for (int i = 0; i < num_addr; i++) printf(" %d: %s\n", i + 1, addressbook[i]); int choice; scanf("%d", &choice); const char *to = addressbook[choice - 1];
// read body from a text file FILE *fp = fopen("message.txt", "r"); if (fp == NULL) { perror("fopen"); return 1; } char body[BUF_SIZE] = ""; char line[256]; while (fgets(line, 256, fp) != NULL) strcat(body, line); fclose(fp);