如何从 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 发送电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

qt5.5.1+vs2010发送邮件

python发送邮件

如何从 mysql 数据库中获取数据并使用 PHP 将其发送给用户? [关闭]

如何从电子邮件正文发送电子邮件?

如何使用php从xampp发送具有匿名名称的电子邮件

如何从 SQL Server 发送电子邮件?