Mailing List (郵件列表)原理簡述及我的perl實現

注: 本文本來是一早要寫的,可是程序寫了有段時間了,最近一段時間又很忙,居然給忘了,現在補上。

正文

大部分IT人員都使用過郵件列表,或者類似的服務,但郵件列表的內部工作原理則不是簡單的訂閱,退訂閱那麽簡單。最近根據自己的一些認識,用perl實現了一個非常簡單的MLM程序,也順便談談郵件列表的最基本工作原理。

郵件列表,簡單的來說,就是任一列表成員向該列表發的郵件,其他所有人(可以包括他自己)都能收到,並且每個人能自由訂閱、退訂。更豐富的郵件列表還包括了摘要,精確權限管理,web archive功能等等。

著名的開源郵件列表軟件如mailman, majodomo, ezmlm, sympa, ecartis等都是功能完備的郵件列表軟件,但歸根結底,最簡單的郵件列表至少應該包含如下功能:

訂閱功能,即用戶發特定訂閱信件到郵件列表 確認訂閱功能,即用戶必須給MLM發確認信才能正式訂閱 退訂功能,用戶可自由退出訂閱服務。 任一列表成員給郵件列表發的郵件,其他人都應收到。 要實現上述的功能,如果使用perl的話並不複雜,配合Postfix MTA可以非常方便的開發出簡易的郵件列表軟件。以下是自己開發的MMList(Mini Mailing List) 的基本結構:

Mailing List (郵件列表)原理簡述及我的perl實現

配置基于Postfix,使用alias的方法,將郵件通過管道送到MMList: main.cf裏需要配置的內容:

alias_maps = hash:/etc/postfix/aliases hash:/etc/postfix/mml.aliasesvirtual_alias_maps = hash:/etc/postfix/mml.virtual_alias_maps

mml.aliases的內容:

# alias filetest-subscribe-hzqbbc.com: "|/usr/bin/mml -cmd=subscribe -list=test@hzqbbc.com"test-confirm-hzqbbc.com: "|/usr/bin/mml -cmd=confirm -list=test@hzqbbc.com"test-unsubscribe-hzqbbc.com: "|/usr/bin/mml -cmd=unsubscribe -list=test@hzqbbc.com"

mml.virtual_alias_maps的內容:

test-subscribe@hzqbbc.com test-subscribe-hzqbbc.comtest-confirm@hzqbbc.com test-confirm-hzqbbc.comtest-unsubscribe@hzqbbc.com test-unsubscribe-hzqbbc.com

MMList 的perl實現#!/usr/bin/perl -w# vim: set cindent expandtab ts=4 sw=4:# MMList - a very lightweight MLM software## Author: He zhiqiang # CopyRight (c) 1998-2005 hzqbbc.com## License: GPL v2use strict;use Getopt::Long;use vars qw(%cfg $cmd $list @KEY_MAP);use vars qw($user $subj $SLOG);$user = $subj = "";@KEY_MAP = ( 0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E', 'F','G','H','I','J','K','L','M','N','O', 'P','Q','R','S','T','U','V','W','X','Y', 'Z','a','b','c','d','e','f','g','h','i', 'j','k','l','m','n','o','p','q','r','s', 't','u','v','w','x','y','z');# PRoto-type:# cmd == indicate the 'subscribe' or 'unsubscribe'# list == indicate the list namemy $res = GetOptions("cmd=s" = \$cmd, "list=s" = \$list);$cfg{'basedir'} = "/var/lib/mmlist";$cfg{'listdir'} = $cfg{'basedir'}."/lists";$cfg{'hostname'} = "list.hzqbbc.com";open (MLOG, " $cfg{'basedir'}/mail.log");open ($SLOG, " $cfg{'basedir'}/base.log");# read from STDINwhile() { print MLOG $_; if(/^From: (.*)$/) { chomp; m/([a-zA-Z0-9-_=\.]+\@[a-zA-Z0-9-_=\.]+)/; if($1) { $user = lc $1; } }elsif(/^Subject: (.*)$/) { chomp; $subj = $1; $subj =~ s/\s//g; }}syslog("cmd = $cmd");if($cmd eq "subscribe") { if(user_exist($user)) { syslog("$user subscribed"); my $body = q(Hey guy, you have already subscribed!); sendmail($user, "Subscribe failure", $body); }else { my $sid = gen_sid(); open(FD, " $cfg{'listdir'}/$list/queue/$user") or syslog("$!") and die "Can't write to $user, $!\n"; printf FD "%s\:%s\n", time, $sid; close FD; syslog("confirm $user"); my $body = "Hey guy, reply to me with the code $sid \n" ."in the subject section\n"; $list =~ m/([^:]+)\@(.*)/; my $from = "$1-confirm\@$2"; sendmail($user, "Confirm subscribe", $body, $from); }}elsif($cmd eq "confirm") { if(not user_exist($user)) { syslog("$user not exist"); if(valid_sid($user, $subj)) { syslog("added $user"); add_user($user); my $body = "Welcome to $list :-)\n"; sendmail($user, "Added to the list", $body); }else { syslog("fail to confirm $user"); my $body = "Hey guy, your confirm fail, please try again\n"; sendmail($user, "Confirm failure", $body); } }else { my $body = "Hey guy, you step into a wrong situation!\n"; sendmail($user, "Wrong action", $body); }}elsif($cmd eq "unsubscribe") { if(user_exist($user)) { syslog("$user removed"); del_user($user); my $body = "Hey guy, you have been removed from the $list\n"; sendmail($user, "Goodbye - from $list", $body); }else { my $body = "Hey guy, you step into a wrong situation!\n"; sendmail($user, "Wrong action", $body); }}else { print STDERR "m3 error cmd!\n"; exit(13);}exit(0);## funcs to handle mail listsub sendmail { my($to, $subj, $body, $from) = @_; if(not defined $from) { $from = "m3\@$cfg{'hostname'}"; } open(CMD, "| /usr/sbin/sendmail -oi -t -f \"$from\" $to") or die "Can't exec /usr/sbin/sendmail, $!\n"; print CMD close CMD;}sub user_exist { my $user = shift; if (! -r "$cfg{'listdir'}/$list/users.txt") { return 0; } open(FD, "or die "Can't open $list, $!\n"; while() { chomp; if(/^$user$/i) { return 1; } } close FD; 0;}# gen_sid - to generate unique session idsub gen_sid { my ($sid, $len) = ("", $_[0] ? $_[0]-1 : 23); srand(time()); foreach(0...$len) { $sid .= $KEY_MAP[int rand(61)]; # total of $#KEY_MAP -1 } $sid;}sub valid_sid { my ($user, $sid) = @_; open(FD, "or syslog("can't open $user, $!") and die "Can't open $user, $!\n"; $_ = ; chomp; ($_) = m/[^:]+:(.*)/; if($sid eq $_) { syslog("auth ok for $user"); return 1; } close FD; return 0;}sub add_user { my ($user) = @_; unlink "$cfg{'listdir'}/$list/queue/$user"; # clean up user cookie/queue open(FD, " $cfg{'listdir'}/$list/users.txt") or die "Can't append to users.txt for $list, $!\n"; print FD $user, "\n"; close FD;}sub del_user { my ($user) = @_; my $buf = undef; open(FD, "or die "Can't open users.txt for $list, $!\n"; while() { chomp; if(!/^$user$/) { $buf.="$_\n"; } } close FD; open(FD, " $cfg{'listdir'}/$list/users.txt") or die "Can't write to users.txt for $list, $!\n"; print FD $buf; close FD;}sub syslog { my ($msg) = @_; chomp $msg; printf $SLOG "%s $msg\n", time;}

在List Control中實現列表項目的上下移動
在List Control中實現列表項目的上下移動 作者/ 前言 List Control是Visual C++的一個通用控件,在很多程序中都有對它的使用,比如Windows ...查看完整版>>在List Control中實現列表項目的上下移動
 
搞笑,剛在PHP mailing list上看到的
PHP General Mailing List上,有人問:WORK WITH PHP FILES REMOTELY WITH NotePad ? YES/NO ?I want to know if when be online I CAN OPEN A FILE FROM A WEB LOCATIONHOST - MINE and after I modify it save it ...查看完整版>>搞笑,剛在PHP mailing list上看到的
 
郵件列表mailman在aix5.1實現
Mailman 是一個能夠幫助管理email 討論列表。與同類産品不同的是,Mailman 能夠將郵件列表顯示在web 頁上,允許用戶訂閱或取消訂閱等等。通過Mailman 可以直接從web 頁上管理自己的郵件列表。它支持虛擬域名、支持大...查看完整版>>郵件列表mailman在aix5.1實現
 
ASP環境下郵件列表功能的實現 (三)(推薦)
在訪問管理頁面之前必須經過身份驗證。本實現中我們用圖3所示的secure.htm頁面供管理員輸入身份識別碼,若用戶輸入值非空則用Cookies來保存它。執行管理任務的頁面是admin.asp,每當用戶試圖訪問這個頁面,下面的代碼...查看完整版>>ASP環境下郵件列表功能的實現 (三)(推薦)
 
ASP環境下郵件列表功能的實現 (二)(推薦)
爲最終用戶提供的功能主要由一個HTML文件和兩個ASP文件提供,它們負責接受用戶的訂閱申請以及退出郵件列表申請。    用戶的個人信息在圖1所示的登記表單中輸入,其實現文件是homepage.htm。當用戶提交...查看完整版>>ASP環境下郵件列表功能的實現 (二)(推薦)
 
ASP環境下郵件列表功能的實現 (二)(推薦)
爲最終用戶提供的功能主要由一個HTML文件和兩個ASP文件提供,它們負責接受用戶的訂閱申請以及退出郵件列表申請。    用戶的個人信息在圖1所示的登記表單中輸入,其實現文件是homepage.htm。當用戶提交...查看完整版>>ASP環境下郵件列表功能的實現 (二)(推薦)
 
ASP環境下郵件列表功能的實現 (一)(推薦)
郵件列表(Mailing List)是當前最受歡迎的網絡服務之一。本文通過一個示例系統的建設,介紹在ASP環境下郵件列表功能的實現方法。    ChinaByte網絡學院的《Java Mail API及其應用》一文介紹了在J...查看完整版>>ASP環境下郵件列表功能的實現 (一)(推薦)
 
Perl教學第四篇列表和數組變量
  一、列表  列表是包含在括號裏的一序列的值,可以爲任何數值,也可爲空,如:(1, 5.3 , "hello" , 2),空列表:()。  注:只含有一個數值的列表(如:(43.2) )與該數值本身(即:43.2 )是不同的,但它們可以互...查看完整版>>Perl教學第四篇列表和數組變量
 
數據庫查詢以及插入LIST列表函數
void CStuDlg::List(CString sql) //將SQL語句查詢的結果顯示在列表框中{ m_MyList.DeleteAllItems(); int i=0; m_pRecordset.CreateInstance("ADODB.Recordset"); m_pRecordset->Open((_variant...查看完整版>>數據庫查詢以及插入LIST列表函數
 
 
回到王朝網路首頁