如何从 MySQL 5.1 发送电子邮件
Posted
技术标签:
【中文标题】如何从 MySQL 5.1 发送电子邮件【英文标题】:How to send email from MySQL 5.1 【发布时间】:2010-09-28 02:22:51 【问题描述】:当新行插入到表中时,我正在尝试向多个收件人发送电子邮件。收件人列表各不相同。我希望能够使用 select 语句设置此列表。 我还安装了 Navicat,它允许我发送电子邮件通知,但只能发送给预定的一组人。
谢谢。
【问题讨论】:
【参考方案1】:我会非常担心将发送电子邮件的负载放在我的数据库服务器上(尽管它可能很小)。我可能会建议以下替代方案之一:
-
让应用程序逻辑检测是否需要发送电子邮件并发送。
让 mysql 触发器填充一个将要发送的电子邮件排队的表,并让进程监控该表并发送电子邮件。
【讨论】:
感谢您的回复!关于选项 2,您将如何实施? 您创建一个表格来保存您要发送的电子邮件消息(可能是主题行和正文的列;但也许您只会参考“form email, id=2”)然后你有一个程序会经常检查这个表是否有新行,如果有新行,就会通过电子邮件发送出去。 只是把它放在那里,但微软有他们的数据库邮件组件,它与数据库在同一台服务器上运行(至少在正常情况下)。这是一个不同的进程/线程,但在同一台服务器上。只是说。 @colithium,这也是 99% 的 LAMP 设置所做的。一台服务器,一切都在上面。 是的,还有 docker-compose,所有东西都在一台服务器上运行:post-fix、dovecot、scala api、java api、c# api、apache、tomcat、nginx、node api、MySQL、python , mongodb, zabbix-agent, ssh, 大声笑【参考方案2】:我同意吉姆·暴雪的观点。数据库不是应该发送电子邮件的技术堆栈的一部分。例如,如果您发送了一封电子邮件,但随后回滚了触发该电子邮件的更改,该怎么办?您无法收回这封电子邮件。
最好在您的应用程序代码层发送电子邮件,在您的应用程序确认 SQL 更改已成功进行并提交之后。
【讨论】:
一个棘手的场景是,当由于级联更新或触发器内部的更改而发生操作时,如何通过电子邮件通知。 @BillKarwin 如果您找到了解决您的评论的方法,请告诉我,我很想知道这一点。 @Harbir,我仍然(六年后)认为数据库不应该发送电子邮件。提交数据库更改后,您应该在应用程序中执行此操作。触发操作的一种策略是让触发器在名为SendEmailTo
的表中插入一行(例如),然后您的应用在提交工作后读取该表。如果该表中有一行,请发送电子邮件并删除该行。
@BillKarwin 这将如何完成?这恰好正是我正在寻找的(更新特定表时获取更新)。你有例子吗?
@webfrogs,试试***.com/questions/18706790/…【参考方案3】:
如果您正在运行 SMTP 服务,您可以将文件输出到投递目录。如果您的容量很大,则可能会导致文件名重复,但有一些方法可以避免这种情况。
否则,您将需要创建 UDF。
这是一个示例触发解决方案:
CREATE TRIGGER test.autosendfromdrop BEFORE INSERT ON test.emaildrop
FOR EACH ROW BEGIN
/* START THE WRITING OF THE EMAIL FILE HERE*/
SELECT concat("To: ",NEW.To),
concat("From: ",NEW.From),
concat("Subject: ",NEW.Subject),
NEW.Body
INTO OUTFILE
"C:\\inetpub\\mailroot\\pickup\\mail.txt"
FIELDS TERMINATED by '\r\n' ESCAPED BY '';
END;
要标记邮件正文,您需要这样的内容...
CREATE FUNCTION `htmlBody`(Msg varchar(8192))
RETURNS varchar(17408) CHARSET latin1 DETERMINISTIC
BEGIN
declare tmpMsg varchar(17408);
set tmpMsg = cast(concat(
'Date: ',date_format(NOW(),'%e %b %Y %H:%i:%S -0600'),'\r\n',
'MIME-Version: 1.0','\r\n',
'Content-Type: multipart/alternative;','\r\n',
' boundary=\"----=_NextPart_000_0000_01CA4B3F.8C263EE0\"','\r\n',
'Content-Class: urn:content-classes:message','\r\n',
'Importance: normal','\r\n',
'Priority: normal','\r\n','','\r\n','','\r\n',
'This is a multi-part message in MIME format.','\r\n','','\r\n',
'------=_NextPart_000_0000_01CA4B3F.8C263EE0','\r\n',
'Content-Type: text/plain;','\r\n',
' charset=\"iso-8859-1\"','\r\n',
'Content-Transfer-Encoding: 7bit','\r\n','','\r\n','','\r\n',
Msg,
'\r\n','','\r\n','','\r\n',
'------=_NextPart_000_0000_01CA4B3F.8C263EE0','\r\n',
'Content-Type: text/html','\r\n',
'Content-Transfer-Encoding: 7bit','\r\n','','\r\n',
Msg,
'\r\n','------=_NextPart_000_0000_01CA4B3F.8C263EE0--'
) as char);
RETURN tmpMsg;
END ;
【讨论】:
【参考方案4】:如果您有 vps 或专用服务器,您可以使用 C 编程编写自己的模块。
para.h
/*
* File: para.h
* Author: rahul
*
* Created on 10 February, 2016, 11:24 AM
*/
#ifndef PARA_H
#define PARA_H
#ifdef __cplusplus
extern "C"
#endif
#define From "<dgdfg@dgfdgd.com>"
#define To "<dfgdfg.dfg@gmail.com>"
#define From_header "Rahul<fdgdfg@dfgdfg.com>"
#define TO_header "Mini<dfgdffefg@gmail.com>"
#define UID "smtp server account ID"
#define PWD "smtp server account PWD"
#define domain "dfgdfgdfg.com"
#ifdef __cplusplus
#endif
#endif
/* PARA_H */
main.c
/*
* File: main.c
* Author: rahul
*
* Created on 10 February, 2016, 10:29 AM
*/
#include <my_global.h>
#include <mysql.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "time.h"
#include "para.h"
/*
*
*/
my_bool SendEmail_init(UDF_INIT *initid,UDF_ARGS *arg,char *message);
void SendEmail_deinit(UDF_INIT *initid __attribute__((unused)));
char* SendEmail(UDF_INIT *initid, UDF_ARGS *arg,char *result,unsigned long *length, char *is_null,char* error);
/*
* base64
*/
int Base64encode_len(int len);
int Base64encode(char * coded_dst, const char *plain_src,int len_plain_src);
int Base64decode_len(const char * coded_src);
int Base64decode(char * plain_dst, const char *coded_src);
/* aaaack but it's fast and const should make it shared text page. */
static const unsigned char pr2six[256] =
/* ASCII table */
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
;
int Base64decode_len(const char *bufcoded)
int nbytesdecoded;
register const unsigned char *bufin;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
return nbytesdecoded + 1;
int Base64decode(char *bufplain, const char *bufcoded)
int nbytesdecoded;
register const unsigned char *bufin;
register unsigned char *bufout;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
bufout = (unsigned char *) bufplain;
bufin = (const unsigned char *) bufcoded;
while (nprbytes > 4)
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
/* Note: (nprbytes == 1) would be an error, so just ingore that case */
if (nprbytes > 1)
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
if (nprbytes > 2)
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
if (nprbytes > 3)
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
*(bufout++) = '\0';
nbytesdecoded -= (4 - nprbytes) & 3;
return nbytesdecoded;
static const char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Base64encode_len(int len)
return ((len + 2) / 3 * 4) + 1;
int Base64encode(char *encoded, const char *string, int len)
int i;
char *p;
p = encoded;
for (i = 0; i < len - 2; i += 3)
*p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2) |
((int) (string[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[string[i + 2] & 0x3F];
if (i < len)
*p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1))
*p++ = basis_64[((string[i] & 0x3) << 4)];
*p++ = '=';
else
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2)];
*p++ = '=';
*p++ = '\0';
return p - encoded;
/*
end of base64
*/
const char* GetIPAddress(const char* target_domain)
const char* target_ip;
struct in_addr *host_address;
struct hostent *raw_list = gethostbyname(target_domain);
int i = 0;
for (i; raw_list->h_addr_list[i] != 0; i++)
host_address = raw_list->h_addr_list[i];
target_ip = inet_ntoa(*host_address);
return target_ip;
char * MailHeader(const char* from, const char* to, const char* subject, const char* mime_type, const char* charset)
time_t now;
time(&now);
char *app_brand = "Codevlog Test APP";
char* mail_header = NULL;
char date_buff[26];
char Branding[6 + strlen(date_buff) + 2 + 10 + strlen(app_brand) + 1 + 1];
char Sender[6 + strlen(from) + 1 + 1];
char Recip[4 + strlen(to) + 1 + 1];
char Subject[8 + 1 + strlen(subject) + 1 + 1];
char mime_data[13 + 1 + 3 + 1 + 1 + 13 + 1 + strlen(mime_type) + 1 + 1 + 8 + strlen(charset) + 1 + 1 + 2];
strftime(date_buff, (33), "%a , %d %b %Y %H:%M:%S", localtime(&now));
sprintf(Branding, "DATE: %s\r\nX-Mailer: %s\r\n", date_buff, app_brand);
sprintf(Sender, "FROM: %s\r\n", from);
sprintf(Recip, "To: %s\r\n", to);
sprintf(Subject, "Subject: %s\r\n", subject);
sprintf(mime_data, "MIME-Version: 1.0\r\nContent-type: %s; charset=%s\r\n\r\n", mime_type, charset);
int mail_header_length = strlen(Branding) + strlen(Sender) + strlen(Recip) + strlen(Subject) + strlen(mime_data) + 10;
mail_header = (char*) malloc(mail_header_length);
memcpy(&mail_header[0], &Branding, strlen(Branding));
memcpy(&mail_header[0 + strlen(Branding)], &Sender, strlen(Sender));
memcpy(&mail_header[0 + strlen(Branding) + strlen(Sender)], &Recip, strlen(Recip));
memcpy(&mail_header[0 + strlen(Branding) + strlen(Sender) + strlen(Recip)], &Subject, strlen(Subject));
memcpy(&mail_header[0 + strlen(Branding) + strlen(Sender) + strlen(Recip) + strlen(Subject)], &mime_data, strlen(mime_data));
return mail_header;
my_bool SendEmail_init(UDF_INIT *initid,UDF_ARGS *arg,char *message)
if (!(arg->arg_count == 2))
strcpy(message, "Expected two arguments");
return 1;
arg->arg_type[0] = STRING_RESULT;// smtp server address
arg->arg_type[1] = STRING_RESULT;// email body
initid->ptr = (char*) malloc(2050 * sizeof (char));
memset(initid->ptr, '\0', sizeof (initid->ptr));
return 0;
void SendEmail_deinit(UDF_INIT *initid __attribute__((unused)))
if (initid->ptr)
free(initid->ptr);
char* SendEmail(UDF_INIT *initid, UDF_ARGS *arg,char *result,unsigned long *length, char *is_null,char* error)
char *header = MailHeader(From_header, TO_header, "Hello Its a test Mail from Codevlog", "text/plain", "US-ASCII");
int connected_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
struct sockaddr_in addr;
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(25);
if (inet_pton(AF_INET, GetIPAddress(arg->args[0]), &addr.sin_addr) == 1)
connect(connected_fd, (struct sockaddr*) &addr, sizeof (addr));
if (connected_fd != -1)
int recvd = 0;
const char recv_buff[4768];
int sdsd;
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char buff[1000];
strcpy(buff, "EHLO "); //"EHLO sdfsdfsdf.com\r\n"
strcat(buff, domain);
strcat(buff, "\r\n");
send(connected_fd, buff, strlen(buff), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char _cmd2[1000];
strcpy(_cmd2, "AUTH LOGIN\r\n");
int dfdf = send(connected_fd, _cmd2, strlen(_cmd2), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char _cmd3[1000];
Base64encode(&_cmd3, UID, strlen(UID));
strcat(_cmd3, "\r\n");
send(connected_fd, _cmd3, strlen(_cmd3), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char _cmd4[1000];
Base64encode(&_cmd4, PWD, strlen(PWD));
strcat(_cmd4, "\r\n");
send(connected_fd, _cmd4, strlen(_cmd4), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char _cmd5[1000];
strcpy(_cmd5, "MAIL FROM: ");
strcat(_cmd5, From);
strcat(_cmd5, "\r\n");
send(connected_fd, _cmd5, strlen(_cmd5), 0);
char skip[1000];
sdsd = recv(connected_fd, skip, sizeof (skip), 0);
char _cmd6[1000];
strcpy(_cmd6, "RCPT TO: ");
strcat(_cmd6, To); //
strcat(_cmd6, "\r\n");
send(connected_fd, _cmd6, strlen(_cmd6), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char _cmd7[1000];
strcpy(_cmd7, "DATA\r\n");
send(connected_fd, _cmd7, strlen(_cmd7), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
send(connected_fd, header, strlen(header), 0);
send(connected_fd, arg->args[1], strlen(arg->args[1]), 0);
char _cmd9[1000];
strcpy(_cmd9, "\r\n.\r\n.");
send(connected_fd, _cmd9, sizeof (_cmd9), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
recvd += sdsd;
char _cmd10[1000];
strcpy(_cmd10, "QUIT\r\n");
send(connected_fd, _cmd10, sizeof (_cmd10), 0);
sdsd = recv(connected_fd, recv_buff + recvd, sizeof (recv_buff) - recvd, 0);
memcpy(initid->ptr, recv_buff, strlen(recv_buff));
*length = recvd;
free(header);
close(connected_fd);
return initid->ptr;
要配置您的项目,请观看此视频: https://www.youtube.com/watch?v=Zm2pKTW5z98(在 Linux 上从 MySQL 发送电子邮件)它适用于任何 mysql 版本(5.5、5.6、5.7)
以上代码如有错误我会解决,请在评论中告知
【讨论】:
以上是关于如何从 MySQL 5.1 发送电子邮件的主要内容,如果未能解决你的问题,请参考以下文章