Fossil SCM
Fixes to the "SMTP relay" alert send method. Add the --smtp-trace option to the "fossil email send" command. Expose and document the "email-send-relayhost" setting.
Commit
006cc8143740974fc64a7ee2c3ed7a56b14e5d8db7c3bb382531bdcf6660c555
Parent
b96415f047707df…
1 file changed
+27
-7
+27
-7
| --- src/email.c | ||
| +++ src/email.c | ||
| @@ -386,12 +386,18 @@ | ||
| 386 | 386 | const char *zCmd; /* Command to run for each email */ |
| 387 | 387 | const char *zFrom; /* Emails come from here */ |
| 388 | 388 | SmtpSession *pSmtp; /* SMTP relay connection */ |
| 389 | 389 | Blob out; /* For zDest=="blob" */ |
| 390 | 390 | char *zErr; /* Error message */ |
| 391 | + u32 mFlags; /* Flags */ | |
| 391 | 392 | int bImmediateFail; /* On any error, call fossil_fatal() */ |
| 392 | 393 | }; |
| 394 | + | |
| 395 | +/* Allowed values for EmailSender flags */ | |
| 396 | +#define EMAIL_IMMEDIATE_FAIL 0x0001 /* Call fossil_fatal() on any error */ | |
| 397 | +#define EMAIL_SMTP_TRACE 0x0002 /* Write SMTP transcript to console */ | |
| 398 | + | |
| 393 | 399 | #endif /* INTERFACE */ |
| 394 | 400 | |
| 395 | 401 | /* |
| 396 | 402 | ** Shutdown an emailer. Clear all information other than the error message. |
| 397 | 403 | */ |
| @@ -402,10 +408,11 @@ | ||
| 402 | 408 | p->db = 0; |
| 403 | 409 | p->zDb = 0; |
| 404 | 410 | p->zDir = 0; |
| 405 | 411 | p->zCmd = 0; |
| 406 | 412 | if( p->pSmtp ){ |
| 413 | + smtp_client_quit(p->pSmtp); | |
| 407 | 414 | smtp_session_free(p->pSmtp); |
| 408 | 415 | p->pSmtp = 0; |
| 409 | 416 | } |
| 410 | 417 | blob_reset(&p->out); |
| 411 | 418 | } |
| @@ -418,11 +425,11 @@ | ||
| 418 | 425 | fossil_free(p->zErr); |
| 419 | 426 | va_start(ap, zFormat); |
| 420 | 427 | p->zErr = vmprintf(zFormat, ap); |
| 421 | 428 | va_end(ap); |
| 422 | 429 | emailerShutdown(p); |
| 423 | - if( p->bImmediateFail ){ | |
| 430 | + if( p->mFlags & EMAIL_IMMEDIATE_FAIL ){ | |
| 424 | 431 | fossil_fatal("%s", p->zErr); |
| 425 | 432 | } |
| 426 | 433 | } |
| 427 | 434 | |
| 428 | 435 | /* |
| @@ -466,17 +473,17 @@ | ||
| 466 | 473 | ** zAltDest to cause all emails to be printed to the console for |
| 467 | 474 | ** debugging purposes. |
| 468 | 475 | ** |
| 469 | 476 | ** The EmailSender object returned must be freed using email_sender_free(). |
| 470 | 477 | */ |
| 471 | -EmailSender *email_sender_new(const char *zAltDest, int bImmediateFail){ | |
| 478 | +EmailSender *email_sender_new(const char *zAltDest, u32 mFlags){ | |
| 472 | 479 | EmailSender *p; |
| 473 | 480 | |
| 474 | 481 | p = fossil_malloc(sizeof(*p)); |
| 475 | 482 | memset(p, 0, sizeof(*p)); |
| 476 | 483 | blob_init(&p->out, 0, 0); |
| 477 | - p->bImmediateFail = bImmediateFail; | |
| 484 | + p->mFlags = mFlags; | |
| 478 | 485 | if( zAltDest ){ |
| 479 | 486 | p->zDest = zAltDest; |
| 480 | 487 | }else{ |
| 481 | 488 | p->zDest = db_get("email-send-method","off"); |
| 482 | 489 | } |
| @@ -515,11 +522,14 @@ | ||
| 515 | 522 | blob_init(&p->out, 0, 0); |
| 516 | 523 | }else if( fossil_strcmp(p->zDest, "relay")==0 ){ |
| 517 | 524 | const char *zRelay = 0; |
| 518 | 525 | emailerGetSetting(p, &zRelay, "email-send-relayhost"); |
| 519 | 526 | if( zRelay ){ |
| 520 | - p->pSmtp = smtp_session_new(p->zFrom, zRelay, SMTP_DIRECT); | |
| 527 | + u32 smtpFlags = SMTP_DIRECT; | |
| 528 | + if( mFlags & EMAIL_SMTP_TRACE ) smtpFlags |= SMTP_TRACE_STDOUT; | |
| 529 | + p->pSmtp = smtp_session_new(p->zFrom, zRelay, smtpFlags); | |
| 530 | + smtp_client_startup(p->pSmtp); | |
| 521 | 531 | } |
| 522 | 532 | } |
| 523 | 533 | return p; |
| 524 | 534 | } |
| 525 | 535 | |
| @@ -729,11 +739,11 @@ | ||
| 729 | 739 | }else if( p->pSmtp ){ |
| 730 | 740 | char **azTo = 0; |
| 731 | 741 | int nTo = 0; |
| 732 | 742 | email_header_to(pHdr, &nTo, &azTo); |
| 733 | 743 | if( nTo>0 ){ |
| 734 | - smtp_send_msg(p->pSmtp, p->zFrom, nTo, azTo, blob_str(&all)); | |
| 744 | + smtp_send_msg(p->pSmtp, p->zFrom, nTo, (const char**)azTo,blob_str(&all)); | |
| 735 | 745 | email_header_to_free(nTo, azTo); |
| 736 | 746 | } |
| 737 | 747 | }else if( strcmp(p->zDest, "stdout")==0 ){ |
| 738 | 748 | char **azTo = 0; |
| 739 | 749 | int nTo = 0; |
| @@ -801,10 +811,17 @@ | ||
| 801 | 811 | ** SETTING: email-receive-dir width=40 |
| 802 | 812 | ** Inbound email messages are saved as separate files in this directory, |
| 803 | 813 | ** for debugging analysis. Disable saving of inbound emails omitting |
| 804 | 814 | ** this setting, or making it an empty string. |
| 805 | 815 | */ |
| 816 | +/* | |
| 817 | +** SETTING: email-send-relayhost width=40 | |
| 818 | +** This is the hostname and TCP port to which output email messages | |
| 819 | +** are sent when email-send-method is "relay". There should be an | |
| 820 | +** SMTP server configured as a Mail Submission Agent listening on the | |
| 821 | +** designated host and port and all times. | |
| 822 | +*/ | |
| 806 | 823 | |
| 807 | 824 | |
| 808 | 825 | /* |
| 809 | 826 | ** COMMAND: email |
| 810 | 827 | ** |
| @@ -833,10 +850,11 @@ | ||
| 833 | 850 | ** email sending mechanism is currently configured. |
| 834 | 851 | ** Use this for testing the email configuration. |
| 835 | 852 | ** Options: |
| 836 | 853 | ** |
| 837 | 854 | ** --body FILENAME |
| 855 | +** --smtp-trace | |
| 838 | 856 | ** --stdout |
| 839 | 857 | ** --subject|-S SUBJECT |
| 840 | 858 | ** |
| 841 | 859 | ** settings [NAME VALUE] With no arguments, list all email settings. |
| 842 | 860 | ** Or change the value of a single email setting. |
| @@ -907,13 +925,15 @@ | ||
| 907 | 925 | }else |
| 908 | 926 | if( strncmp(zCmd, "send", nCmd)==0 ){ |
| 909 | 927 | Blob prompt, body, hdr; |
| 910 | 928 | const char *zDest = find_option("stdout",0,0)!=0 ? "stdout" : 0; |
| 911 | 929 | int i; |
| 930 | + u32 mFlags = EMAIL_IMMEDIATE_FAIL; | |
| 912 | 931 | const char *zSubject = find_option("subject", "S", 1); |
| 913 | 932 | const char *zSource = find_option("body", 0, 1); |
| 914 | 933 | EmailSender *pSender; |
| 934 | + if( find_option("smtp-trace",0,0)!=0 ) mFlags |= EMAIL_SMTP_TRACE; | |
| 915 | 935 | verify_all_options(); |
| 916 | 936 | blob_init(&prompt, 0, 0); |
| 917 | 937 | blob_init(&body, 0, 0); |
| 918 | 938 | blob_init(&hdr, 0, 0); |
| 919 | 939 | blob_appendf(&hdr,"To: "); |
| @@ -929,11 +949,11 @@ | ||
| 929 | 949 | blob_read_from_file(&body, zSource, ExtFILE); |
| 930 | 950 | }else{ |
| 931 | 951 | prompt_for_user_comment(&body, &prompt); |
| 932 | 952 | } |
| 933 | 953 | blob_add_final_newline(&body); |
| 934 | - pSender = email_sender_new(zDest, 1); | |
| 954 | + pSender = email_sender_new(zDest, mFlags); | |
| 935 | 955 | email_send(pSender, &hdr, &body); |
| 936 | 956 | email_sender_free(pSender); |
| 937 | 957 | blob_reset(&hdr); |
| 938 | 958 | blob_reset(&body); |
| 939 | 959 | blob_reset(&prompt); |
| @@ -1179,11 +1199,11 @@ | ||
| 1179 | 1199 | /* We need to send a verification email */ |
| 1180 | 1200 | Blob hdr, body; |
| 1181 | 1201 | EmailSender *pSender = email_sender_new(0,0); |
| 1182 | 1202 | blob_init(&hdr,0,0); |
| 1183 | 1203 | blob_init(&body,0,0); |
| 1184 | - blob_appendf(&hdr, "To: %s\n", zEAddr); | |
| 1204 | + blob_appendf(&hdr, "To: <%s>\n", zEAddr); | |
| 1185 | 1205 | blob_appendf(&hdr, "Subject: Subscription verification\n"); |
| 1186 | 1206 | blob_appendf(&body, zConfirmMsg/*works-like:"%s%s%s"*/, |
| 1187 | 1207 | g.zBaseURL, g.zBaseURL, zCode); |
| 1188 | 1208 | email_send(pSender, &hdr, &body); |
| 1189 | 1209 | style_header("Email Alert Verification"); |
| 1190 | 1210 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -386,12 +386,18 @@ | |
| 386 | const char *zCmd; /* Command to run for each email */ |
| 387 | const char *zFrom; /* Emails come from here */ |
| 388 | SmtpSession *pSmtp; /* SMTP relay connection */ |
| 389 | Blob out; /* For zDest=="blob" */ |
| 390 | char *zErr; /* Error message */ |
| 391 | int bImmediateFail; /* On any error, call fossil_fatal() */ |
| 392 | }; |
| 393 | #endif /* INTERFACE */ |
| 394 | |
| 395 | /* |
| 396 | ** Shutdown an emailer. Clear all information other than the error message. |
| 397 | */ |
| @@ -402,10 +408,11 @@ | |
| 402 | p->db = 0; |
| 403 | p->zDb = 0; |
| 404 | p->zDir = 0; |
| 405 | p->zCmd = 0; |
| 406 | if( p->pSmtp ){ |
| 407 | smtp_session_free(p->pSmtp); |
| 408 | p->pSmtp = 0; |
| 409 | } |
| 410 | blob_reset(&p->out); |
| 411 | } |
| @@ -418,11 +425,11 @@ | |
| 418 | fossil_free(p->zErr); |
| 419 | va_start(ap, zFormat); |
| 420 | p->zErr = vmprintf(zFormat, ap); |
| 421 | va_end(ap); |
| 422 | emailerShutdown(p); |
| 423 | if( p->bImmediateFail ){ |
| 424 | fossil_fatal("%s", p->zErr); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | /* |
| @@ -466,17 +473,17 @@ | |
| 466 | ** zAltDest to cause all emails to be printed to the console for |
| 467 | ** debugging purposes. |
| 468 | ** |
| 469 | ** The EmailSender object returned must be freed using email_sender_free(). |
| 470 | */ |
| 471 | EmailSender *email_sender_new(const char *zAltDest, int bImmediateFail){ |
| 472 | EmailSender *p; |
| 473 | |
| 474 | p = fossil_malloc(sizeof(*p)); |
| 475 | memset(p, 0, sizeof(*p)); |
| 476 | blob_init(&p->out, 0, 0); |
| 477 | p->bImmediateFail = bImmediateFail; |
| 478 | if( zAltDest ){ |
| 479 | p->zDest = zAltDest; |
| 480 | }else{ |
| 481 | p->zDest = db_get("email-send-method","off"); |
| 482 | } |
| @@ -515,11 +522,14 @@ | |
| 515 | blob_init(&p->out, 0, 0); |
| 516 | }else if( fossil_strcmp(p->zDest, "relay")==0 ){ |
| 517 | const char *zRelay = 0; |
| 518 | emailerGetSetting(p, &zRelay, "email-send-relayhost"); |
| 519 | if( zRelay ){ |
| 520 | p->pSmtp = smtp_session_new(p->zFrom, zRelay, SMTP_DIRECT); |
| 521 | } |
| 522 | } |
| 523 | return p; |
| 524 | } |
| 525 | |
| @@ -729,11 +739,11 @@ | |
| 729 | }else if( p->pSmtp ){ |
| 730 | char **azTo = 0; |
| 731 | int nTo = 0; |
| 732 | email_header_to(pHdr, &nTo, &azTo); |
| 733 | if( nTo>0 ){ |
| 734 | smtp_send_msg(p->pSmtp, p->zFrom, nTo, azTo, blob_str(&all)); |
| 735 | email_header_to_free(nTo, azTo); |
| 736 | } |
| 737 | }else if( strcmp(p->zDest, "stdout")==0 ){ |
| 738 | char **azTo = 0; |
| 739 | int nTo = 0; |
| @@ -801,10 +811,17 @@ | |
| 801 | ** SETTING: email-receive-dir width=40 |
| 802 | ** Inbound email messages are saved as separate files in this directory, |
| 803 | ** for debugging analysis. Disable saving of inbound emails omitting |
| 804 | ** this setting, or making it an empty string. |
| 805 | */ |
| 806 | |
| 807 | |
| 808 | /* |
| 809 | ** COMMAND: email |
| 810 | ** |
| @@ -833,10 +850,11 @@ | |
| 833 | ** email sending mechanism is currently configured. |
| 834 | ** Use this for testing the email configuration. |
| 835 | ** Options: |
| 836 | ** |
| 837 | ** --body FILENAME |
| 838 | ** --stdout |
| 839 | ** --subject|-S SUBJECT |
| 840 | ** |
| 841 | ** settings [NAME VALUE] With no arguments, list all email settings. |
| 842 | ** Or change the value of a single email setting. |
| @@ -907,13 +925,15 @@ | |
| 907 | }else |
| 908 | if( strncmp(zCmd, "send", nCmd)==0 ){ |
| 909 | Blob prompt, body, hdr; |
| 910 | const char *zDest = find_option("stdout",0,0)!=0 ? "stdout" : 0; |
| 911 | int i; |
| 912 | const char *zSubject = find_option("subject", "S", 1); |
| 913 | const char *zSource = find_option("body", 0, 1); |
| 914 | EmailSender *pSender; |
| 915 | verify_all_options(); |
| 916 | blob_init(&prompt, 0, 0); |
| 917 | blob_init(&body, 0, 0); |
| 918 | blob_init(&hdr, 0, 0); |
| 919 | blob_appendf(&hdr,"To: "); |
| @@ -929,11 +949,11 @@ | |
| 929 | blob_read_from_file(&body, zSource, ExtFILE); |
| 930 | }else{ |
| 931 | prompt_for_user_comment(&body, &prompt); |
| 932 | } |
| 933 | blob_add_final_newline(&body); |
| 934 | pSender = email_sender_new(zDest, 1); |
| 935 | email_send(pSender, &hdr, &body); |
| 936 | email_sender_free(pSender); |
| 937 | blob_reset(&hdr); |
| 938 | blob_reset(&body); |
| 939 | blob_reset(&prompt); |
| @@ -1179,11 +1199,11 @@ | |
| 1179 | /* We need to send a verification email */ |
| 1180 | Blob hdr, body; |
| 1181 | EmailSender *pSender = email_sender_new(0,0); |
| 1182 | blob_init(&hdr,0,0); |
| 1183 | blob_init(&body,0,0); |
| 1184 | blob_appendf(&hdr, "To: %s\n", zEAddr); |
| 1185 | blob_appendf(&hdr, "Subject: Subscription verification\n"); |
| 1186 | blob_appendf(&body, zConfirmMsg/*works-like:"%s%s%s"*/, |
| 1187 | g.zBaseURL, g.zBaseURL, zCode); |
| 1188 | email_send(pSender, &hdr, &body); |
| 1189 | style_header("Email Alert Verification"); |
| 1190 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -386,12 +386,18 @@ | |
| 386 | const char *zCmd; /* Command to run for each email */ |
| 387 | const char *zFrom; /* Emails come from here */ |
| 388 | SmtpSession *pSmtp; /* SMTP relay connection */ |
| 389 | Blob out; /* For zDest=="blob" */ |
| 390 | char *zErr; /* Error message */ |
| 391 | u32 mFlags; /* Flags */ |
| 392 | int bImmediateFail; /* On any error, call fossil_fatal() */ |
| 393 | }; |
| 394 | |
| 395 | /* Allowed values for EmailSender flags */ |
| 396 | #define EMAIL_IMMEDIATE_FAIL 0x0001 /* Call fossil_fatal() on any error */ |
| 397 | #define EMAIL_SMTP_TRACE 0x0002 /* Write SMTP transcript to console */ |
| 398 | |
| 399 | #endif /* INTERFACE */ |
| 400 | |
| 401 | /* |
| 402 | ** Shutdown an emailer. Clear all information other than the error message. |
| 403 | */ |
| @@ -402,10 +408,11 @@ | |
| 408 | p->db = 0; |
| 409 | p->zDb = 0; |
| 410 | p->zDir = 0; |
| 411 | p->zCmd = 0; |
| 412 | if( p->pSmtp ){ |
| 413 | smtp_client_quit(p->pSmtp); |
| 414 | smtp_session_free(p->pSmtp); |
| 415 | p->pSmtp = 0; |
| 416 | } |
| 417 | blob_reset(&p->out); |
| 418 | } |
| @@ -418,11 +425,11 @@ | |
| 425 | fossil_free(p->zErr); |
| 426 | va_start(ap, zFormat); |
| 427 | p->zErr = vmprintf(zFormat, ap); |
| 428 | va_end(ap); |
| 429 | emailerShutdown(p); |
| 430 | if( p->mFlags & EMAIL_IMMEDIATE_FAIL ){ |
| 431 | fossil_fatal("%s", p->zErr); |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | /* |
| @@ -466,17 +473,17 @@ | |
| 473 | ** zAltDest to cause all emails to be printed to the console for |
| 474 | ** debugging purposes. |
| 475 | ** |
| 476 | ** The EmailSender object returned must be freed using email_sender_free(). |
| 477 | */ |
| 478 | EmailSender *email_sender_new(const char *zAltDest, u32 mFlags){ |
| 479 | EmailSender *p; |
| 480 | |
| 481 | p = fossil_malloc(sizeof(*p)); |
| 482 | memset(p, 0, sizeof(*p)); |
| 483 | blob_init(&p->out, 0, 0); |
| 484 | p->mFlags = mFlags; |
| 485 | if( zAltDest ){ |
| 486 | p->zDest = zAltDest; |
| 487 | }else{ |
| 488 | p->zDest = db_get("email-send-method","off"); |
| 489 | } |
| @@ -515,11 +522,14 @@ | |
| 522 | blob_init(&p->out, 0, 0); |
| 523 | }else if( fossil_strcmp(p->zDest, "relay")==0 ){ |
| 524 | const char *zRelay = 0; |
| 525 | emailerGetSetting(p, &zRelay, "email-send-relayhost"); |
| 526 | if( zRelay ){ |
| 527 | u32 smtpFlags = SMTP_DIRECT; |
| 528 | if( mFlags & EMAIL_SMTP_TRACE ) smtpFlags |= SMTP_TRACE_STDOUT; |
| 529 | p->pSmtp = smtp_session_new(p->zFrom, zRelay, smtpFlags); |
| 530 | smtp_client_startup(p->pSmtp); |
| 531 | } |
| 532 | } |
| 533 | return p; |
| 534 | } |
| 535 | |
| @@ -729,11 +739,11 @@ | |
| 739 | }else if( p->pSmtp ){ |
| 740 | char **azTo = 0; |
| 741 | int nTo = 0; |
| 742 | email_header_to(pHdr, &nTo, &azTo); |
| 743 | if( nTo>0 ){ |
| 744 | smtp_send_msg(p->pSmtp, p->zFrom, nTo, (const char**)azTo,blob_str(&all)); |
| 745 | email_header_to_free(nTo, azTo); |
| 746 | } |
| 747 | }else if( strcmp(p->zDest, "stdout")==0 ){ |
| 748 | char **azTo = 0; |
| 749 | int nTo = 0; |
| @@ -801,10 +811,17 @@ | |
| 811 | ** SETTING: email-receive-dir width=40 |
| 812 | ** Inbound email messages are saved as separate files in this directory, |
| 813 | ** for debugging analysis. Disable saving of inbound emails omitting |
| 814 | ** this setting, or making it an empty string. |
| 815 | */ |
| 816 | /* |
| 817 | ** SETTING: email-send-relayhost width=40 |
| 818 | ** This is the hostname and TCP port to which output email messages |
| 819 | ** are sent when email-send-method is "relay". There should be an |
| 820 | ** SMTP server configured as a Mail Submission Agent listening on the |
| 821 | ** designated host and port and all times. |
| 822 | */ |
| 823 | |
| 824 | |
| 825 | /* |
| 826 | ** COMMAND: email |
| 827 | ** |
| @@ -833,10 +850,11 @@ | |
| 850 | ** email sending mechanism is currently configured. |
| 851 | ** Use this for testing the email configuration. |
| 852 | ** Options: |
| 853 | ** |
| 854 | ** --body FILENAME |
| 855 | ** --smtp-trace |
| 856 | ** --stdout |
| 857 | ** --subject|-S SUBJECT |
| 858 | ** |
| 859 | ** settings [NAME VALUE] With no arguments, list all email settings. |
| 860 | ** Or change the value of a single email setting. |
| @@ -907,13 +925,15 @@ | |
| 925 | }else |
| 926 | if( strncmp(zCmd, "send", nCmd)==0 ){ |
| 927 | Blob prompt, body, hdr; |
| 928 | const char *zDest = find_option("stdout",0,0)!=0 ? "stdout" : 0; |
| 929 | int i; |
| 930 | u32 mFlags = EMAIL_IMMEDIATE_FAIL; |
| 931 | const char *zSubject = find_option("subject", "S", 1); |
| 932 | const char *zSource = find_option("body", 0, 1); |
| 933 | EmailSender *pSender; |
| 934 | if( find_option("smtp-trace",0,0)!=0 ) mFlags |= EMAIL_SMTP_TRACE; |
| 935 | verify_all_options(); |
| 936 | blob_init(&prompt, 0, 0); |
| 937 | blob_init(&body, 0, 0); |
| 938 | blob_init(&hdr, 0, 0); |
| 939 | blob_appendf(&hdr,"To: "); |
| @@ -929,11 +949,11 @@ | |
| 949 | blob_read_from_file(&body, zSource, ExtFILE); |
| 950 | }else{ |
| 951 | prompt_for_user_comment(&body, &prompt); |
| 952 | } |
| 953 | blob_add_final_newline(&body); |
| 954 | pSender = email_sender_new(zDest, mFlags); |
| 955 | email_send(pSender, &hdr, &body); |
| 956 | email_sender_free(pSender); |
| 957 | blob_reset(&hdr); |
| 958 | blob_reset(&body); |
| 959 | blob_reset(&prompt); |
| @@ -1179,11 +1199,11 @@ | |
| 1199 | /* We need to send a verification email */ |
| 1200 | Blob hdr, body; |
| 1201 | EmailSender *pSender = email_sender_new(0,0); |
| 1202 | blob_init(&hdr,0,0); |
| 1203 | blob_init(&body,0,0); |
| 1204 | blob_appendf(&hdr, "To: <%s>\n", zEAddr); |
| 1205 | blob_appendf(&hdr, "Subject: Subscription verification\n"); |
| 1206 | blob_appendf(&body, zConfirmMsg/*works-like:"%s%s%s"*/, |
| 1207 | g.zBaseURL, g.zBaseURL, zCode); |
| 1208 | email_send(pSender, &hdr, &body); |
| 1209 | style_header("Email Alert Verification"); |
| 1210 |