Fossil SCM

For email notifications abound events from a single user (such as individual forum post notifications) make the From: address be a "noreply" hash based on the users human-readable name or handle. Always include a Return-Path: field in the header that is the email-self setting, to be used by MTUs that need to bounce the message.

drh 2018-08-16 18:56 trunk
Commit 475c9d11e9028f9b060b3b57c0b15e6749e176ba6dd3bb46cef776d78cb809ff
1 file changed +56 -4
+56 -4
--- src/email.c
+++ src/email.c
@@ -238,15 +238,18 @@
238238
@ email alert text. Omit the trailing "/".
239239
@ Suggested value: "%h(g.zBaseURL)"
240240
@ (Property: "email-url")</p>
241241
@ <hr>
242242
243
- entry_attribute("\"From\" email address", 20, "email-self",
243
+ entry_attribute("\"Return-Path\" email address", 20, "email-self",
244244
"eself", "", 0);
245245
@ <p><b>Required.</b>
246
- @ This is the email from which email notifications are sent. The
247
- @ system administrator should arrange for emails sent to this address
246
+ @ This is the email to which email notification bounces should be sent.
247
+ @ In cases where the email notification does not align with a specific
248
+ @ Fossil login account (for example, digest messages), this is also
249
+ @ the "From:" address of the email notification.
250
+ @ The system administrator should arrange for emails sent to this address
248251
@ to be handed off to the "fossil email incoming" command so that Fossil
249252
@ can handle bounces. (Property: "email-self")</p>
250253
@ <hr>
251254
252255
entry_attribute("Repository Nickname", 16, "email-subname",
@@ -669,10 +672,49 @@
669672
}else{
670673
z = (char*)zAddr;
671674
}
672675
return z;
673676
}
677
+
678
+/*
679
+** Return a pointer to a fake email mailbox name that corresponds
680
+** to human-readable name zFromName. The fake mailbox name is based
681
+** on a hash. No huge problems arise if there is a hash collisions,
682
+** but it is still better if collisions can be avoided.
683
+**
684
+** The returned string is held in a static buffer and is overwritten
685
+** by each subsequent call to this routine.
686
+*/
687
+static char *email_mailbox_name(const char *zFromName){
688
+ static char zHash[20];
689
+ unsigned int x = 0;
690
+ int n = 0;
691
+ while( zFromName[0] ){
692
+ n++;
693
+ x = x*1103515245 + 12345 + ((unsigned char*)zFromName)[0];
694
+ zFromName++;
695
+ }
696
+ sqlite3_snprintf(sizeof(zHash), zHash,
697
+ "noreply%x%08x", n, x);
698
+ return zHash;
699
+}
700
+
701
+/*
702
+** COMMAND: test-mailbox-hashname
703
+**
704
+** Usage: %fossil test-mailbox-hashname HUMAN-NAME ...
705
+**
706
+** Return the mailbox hash name corresponding to each human-readable
707
+** name on the command line. This is a test interface for the
708
+** email_mailbox_name() function.
709
+*/
710
+void email_test_mailbox_hashname(void){
711
+ int i;
712
+ for(i=2; i<g.argc; i++){
713
+ fossil_print("%30s: %s\n", g.argv[i], email_mailbox_name(g.argv[i]));
714
+ }
715
+}
674716
675717
/*
676718
** Extract all To: header values from the email header supplied.
677719
** Store them in the array list.
678720
*/
@@ -714,19 +756,27 @@
714756
** "In-Reply-To:".
715757
**
716758
** This routine will add fields to the header as follows:
717759
**
718760
** From:
761
+** Return-Path:
719762
** Date:
720763
** Message-Id:
721764
** Content-Type:
722765
** Content-Transfer-Encoding:
723766
** MIME-Version:
724767
**
725768
** The caller maintains ownership of the input Blobs. This routine will
726769
** read the Blobs and send them onward to the email system, but it will
727770
** not free them.
771
+**
772
+** If the zFromName argument is not NULL, then it should be a human-readable
773
+** name or handle for the sender. In that case, "From:" becomes a made-up
774
+** email address based on a hash of zFromName and the domain of email-self,
775
+** and an additional "Reply-To:" field is inserted with the email-self
776
+** address. If zFromName is a NULL pointer, then both "From:" and
777
+** Return-Path: are set to the email-self value.
728778
*/
729779
void email_send(
730780
EmailSender *p, /* Emailer context */
731781
Blob *pHdr, /* Email header (incomplete) */
732782
Blob *pBody, /* Email body */
@@ -749,14 +799,16 @@
749799
blob_init(&all, 0, 0);
750800
pOut = &all;
751801
}
752802
blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
753803
if( zFromName ){
754
- blob_appendf(pOut, "From: %s <%s>\r\n", zFromName, p->zFrom);
804
+ blob_appendf(pOut, "From: %s <%s@%s>\r\n",
805
+ zFromName, email_mailbox_name(zFromName), email_hostname(p->zFrom));
755806
}else{
756807
blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
757808
}
809
+ blob_appendf(pOut, "Return-Path: <%s>\r\n", p->zFrom);
758810
blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
759811
if( strstr(blob_str(pHdr), "\r\nMessage-Id:")==0 ){
760812
/* Message-id format: "<$(date)x$(random).$(from)>" where $(date) is
761813
** the current unix-time in hex, $(random) is a 64-bit random number,
762814
** and $(from) is the sender. */
763815
--- src/email.c
+++ src/email.c
@@ -238,15 +238,18 @@
238 @ email alert text. Omit the trailing "/".
239 @ Suggested value: "%h(g.zBaseURL)"
240 @ (Property: "email-url")</p>
241 @ <hr>
242
243 entry_attribute("\"From\" email address", 20, "email-self",
244 "eself", "", 0);
245 @ <p><b>Required.</b>
246 @ This is the email from which email notifications are sent. The
247 @ system administrator should arrange for emails sent to this address
 
 
 
248 @ to be handed off to the "fossil email incoming" command so that Fossil
249 @ can handle bounces. (Property: "email-self")</p>
250 @ <hr>
251
252 entry_attribute("Repository Nickname", 16, "email-subname",
@@ -669,10 +672,49 @@
669 }else{
670 z = (char*)zAddr;
671 }
672 return z;
673 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
675 /*
676 ** Extract all To: header values from the email header supplied.
677 ** Store them in the array list.
678 */
@@ -714,19 +756,27 @@
714 ** "In-Reply-To:".
715 **
716 ** This routine will add fields to the header as follows:
717 **
718 ** From:
 
719 ** Date:
720 ** Message-Id:
721 ** Content-Type:
722 ** Content-Transfer-Encoding:
723 ** MIME-Version:
724 **
725 ** The caller maintains ownership of the input Blobs. This routine will
726 ** read the Blobs and send them onward to the email system, but it will
727 ** not free them.
 
 
 
 
 
 
 
728 */
729 void email_send(
730 EmailSender *p, /* Emailer context */
731 Blob *pHdr, /* Email header (incomplete) */
732 Blob *pBody, /* Email body */
@@ -749,14 +799,16 @@
749 blob_init(&all, 0, 0);
750 pOut = &all;
751 }
752 blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
753 if( zFromName ){
754 blob_appendf(pOut, "From: %s <%s>\r\n", zFromName, p->zFrom);
 
755 }else{
756 blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
757 }
 
758 blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
759 if( strstr(blob_str(pHdr), "\r\nMessage-Id:")==0 ){
760 /* Message-id format: "<$(date)x$(random).$(from)>" where $(date) is
761 ** the current unix-time in hex, $(random) is a 64-bit random number,
762 ** and $(from) is the sender. */
763
--- src/email.c
+++ src/email.c
@@ -238,15 +238,18 @@
238 @ email alert text. Omit the trailing "/".
239 @ Suggested value: "%h(g.zBaseURL)"
240 @ (Property: "email-url")</p>
241 @ <hr>
242
243 entry_attribute("\"Return-Path\" email address", 20, "email-self",
244 "eself", "", 0);
245 @ <p><b>Required.</b>
246 @ This is the email to which email notification bounces should be sent.
247 @ In cases where the email notification does not align with a specific
248 @ Fossil login account (for example, digest messages), this is also
249 @ the "From:" address of the email notification.
250 @ The system administrator should arrange for emails sent to this address
251 @ to be handed off to the "fossil email incoming" command so that Fossil
252 @ can handle bounces. (Property: "email-self")</p>
253 @ <hr>
254
255 entry_attribute("Repository Nickname", 16, "email-subname",
@@ -669,10 +672,49 @@
672 }else{
673 z = (char*)zAddr;
674 }
675 return z;
676 }
677
678 /*
679 ** Return a pointer to a fake email mailbox name that corresponds
680 ** to human-readable name zFromName. The fake mailbox name is based
681 ** on a hash. No huge problems arise if there is a hash collisions,
682 ** but it is still better if collisions can be avoided.
683 **
684 ** The returned string is held in a static buffer and is overwritten
685 ** by each subsequent call to this routine.
686 */
687 static char *email_mailbox_name(const char *zFromName){
688 static char zHash[20];
689 unsigned int x = 0;
690 int n = 0;
691 while( zFromName[0] ){
692 n++;
693 x = x*1103515245 + 12345 + ((unsigned char*)zFromName)[0];
694 zFromName++;
695 }
696 sqlite3_snprintf(sizeof(zHash), zHash,
697 "noreply%x%08x", n, x);
698 return zHash;
699 }
700
701 /*
702 ** COMMAND: test-mailbox-hashname
703 **
704 ** Usage: %fossil test-mailbox-hashname HUMAN-NAME ...
705 **
706 ** Return the mailbox hash name corresponding to each human-readable
707 ** name on the command line. This is a test interface for the
708 ** email_mailbox_name() function.
709 */
710 void email_test_mailbox_hashname(void){
711 int i;
712 for(i=2; i<g.argc; i++){
713 fossil_print("%30s: %s\n", g.argv[i], email_mailbox_name(g.argv[i]));
714 }
715 }
716
717 /*
718 ** Extract all To: header values from the email header supplied.
719 ** Store them in the array list.
720 */
@@ -714,19 +756,27 @@
756 ** "In-Reply-To:".
757 **
758 ** This routine will add fields to the header as follows:
759 **
760 ** From:
761 ** Return-Path:
762 ** Date:
763 ** Message-Id:
764 ** Content-Type:
765 ** Content-Transfer-Encoding:
766 ** MIME-Version:
767 **
768 ** The caller maintains ownership of the input Blobs. This routine will
769 ** read the Blobs and send them onward to the email system, but it will
770 ** not free them.
771 **
772 ** If the zFromName argument is not NULL, then it should be a human-readable
773 ** name or handle for the sender. In that case, "From:" becomes a made-up
774 ** email address based on a hash of zFromName and the domain of email-self,
775 ** and an additional "Reply-To:" field is inserted with the email-self
776 ** address. If zFromName is a NULL pointer, then both "From:" and
777 ** Return-Path: are set to the email-self value.
778 */
779 void email_send(
780 EmailSender *p, /* Emailer context */
781 Blob *pHdr, /* Email header (incomplete) */
782 Blob *pBody, /* Email body */
@@ -749,14 +799,16 @@
799 blob_init(&all, 0, 0);
800 pOut = &all;
801 }
802 blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
803 if( zFromName ){
804 blob_appendf(pOut, "From: %s <%s@%s>\r\n",
805 zFromName, email_mailbox_name(zFromName), email_hostname(p->zFrom));
806 }else{
807 blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
808 }
809 blob_appendf(pOut, "Return-Path: <%s>\r\n", p->zFrom);
810 blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
811 if( strstr(blob_str(pHdr), "\r\nMessage-Id:")==0 ){
812 /* Message-id format: "<$(date)x$(random).$(from)>" where $(date) is
813 ** the current unix-time in hex, $(random) is a 64-bit random number,
814 ** and $(from) is the sender. */
815

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button