请教如何发送html格式邮件的问题。(200分)

U

UKing

Unregistered / Unconfirmed
GUEST, unregistred user!
我要做的邮件群发是:用户收到的邮件是html格式的,但是显示的数据每个人是不同的。
所以有两个问题,1、如何发送html格式的邮件,2、是如何将不同的数据加入到html邮件
中。(例如html邮件中有表格,要在表格中加入不同的数据);
我现在用的是NMSMTP和RXRICHEDIT控件,已经实现了普通文本邮件的发送。

 
你可以用DHTML控件,從delphi上可以import過來,也可以到microsoft下載(沒必要)
另外NMSMTP發郵件會有問題,不能驗證用戶。通過pop驗證無法發給自己(Outlook
,foxmail都是這樣),群發功能,好像也不怎麼樣,建議用TidSMTP,Delphi6有
有問題可以發email給我zhao-zhenhua@163.net
 
我的意思是,从数据库中读出一段数据,加在html邮件正文的表格里,发送出去给一个
用户,然后再读一段数据,再发给另一个用户。邮件本身就象一个模板,只是在里面
添加数据然后发给不同的用户而已。
不知道现在是不是说明白了。
群发的效率倒不怎么考虑,从数据库中读出地址,一个一个发就是。应该可以忍受。
 
你从库里读出来后,使用 Format 函数将读出的内容写入待发的邮件的 %x 位置。
 
把HTML的文件进行Base64编码然后发送
 
做一個模板,讀出前半部份+MyString+後
 
自己构造 MIME 格式。只要了解MIME格式就行了。
看这篇文章:作者:Kartic Krishnamurthy 译者:limodou

  已经厌倦了给你的朋友和客户发送那些单调乏味的文本通知和信件了吗?曾经考虑过发送附件或在邮中
嵌入HTML吧。

  答案就是MIME。接下来的几页解释了MIME的基础知识,创建符合MIME的信息,然后用一个可以工作的PHP
类结束,这个类实现了发送符合MIME邮件。注意对调用脚本,调用者等等的引用表示使用了将要开发的类的
脚本,客户程序/MUA等等表示邮件阅读的客户程序或邮件使用代理程序。


一些MIME基础
  MIME表示多用途Internet邮件扩允协议。MIME扩允了基本的面向文本的Internet邮件系统,以便可以在
消息中包含二进制附件。

  MIME利用了一个事实就是,RFC 822在消息体的内容中做了一点限制:唯一的限制就是只能使用简单的
ASCII文本。所以,MIME信息由正常的Internet文本邮件组成,文本邮件拥有一些特别的符合RFC 822的信息
头和格式化过的信息体(用ASCII 的子集来表示的附件)。这些MIME头给出了一种在邮件中表示附件的特别
的方法。

MIME信息的剖析
  一个普通的文本邮件的信息包含一个头部分(To: From: Subject: 等等)和一个体部分(Hello Mr.,
等等)。在一个符合MIME的信息中,也包含一个信息头并不奇怪,邮件的各个部分叫做MIME段,每段前也缀
以一个特别的头。MIME邮件只是基于RFC 822邮件的一个扩展。然而它有着自已的RFC规范集。


头字段
  MIME头根据在邮件包中的位置,大体上分为MIME信息头和MIME段头。(译者:MIME信息头指整个邮件
的头,而MIME段头只每个MIME段的头。)

MIME信息头有:

MIME-Version:
这个头提供了所用MIME的版本号。这个值习惯上为1.0。
Content-Type:
它定义了数据的类型,以便数据能被适当的处理。有效的类型有:text,image,audio,video,
applications,multipart和message。注意任何一个二进制附件都应该被叫做application/octet-
stream。这个头的一些用例为:image/jpg, application/mswork,multipart/mixed,这只是很少的
一部分。
Content-Transfer-Encoding:
这是所有头中最重要的一个,因为它说明了对数据所执行的编码方式,客户/MUA 将用它对附件进行解
码。对于每个附件,可以使用7bit,8bit,binary ,quoted-printable,base64和custom中的一种编
码方式。7bit编码是用在US ASCII字符集上的常用的一种编码方式,也就是,保持它的原样。8bit 和
binary编码一般不用。对人类可读的标准文本,如果传输要经过对格式有影响的网关时对其进行保护,
可以使用quoted printable 。Base64是一种通用方法,在需要决定使用哪一种编码方法时,它提供了
一个不用费脑子的选择;它通常用在二进制,非文本数据上。注意,任何非7bit 数据必须用一种模式
编码,这样它就可以通过Internet邮件网关!
Content-ID:
如果Content-Type是message/external-body或multipart/alternative时,这个头就有用了。它超出了本文的范围。
Content-Description:
这是一个可选的头。它是任何信息段内容的自由文本描述。描述必须使用us-ascii码。
Content-Disposition:
一个试验性的头,它用于给客户程序/MUA提供提示,来决定是否在行内显示附件或作为单独的附件。
  MIME段头(出现在实际的MIME附件部分的头),除了MIME-Version头,可以拥有以上任何头字段。如果一个MIME头是信息块的一部分,它将作用于整个信息体。例如,如果Content-Transfer-Encoding显示在信息(指整个信息)头中,它应用于整个信息体,但是如果它显示在一个MIME段里,它"只能"用于那个段中。

下一页


转自phpbuilder.com

作者:Kartic Krishnamurthy 译者:limodou

"好,如何创建符合MIME的信息呢?"
  通过上面的一般性的描述,让我们现在看一下所谓的MIME信息到底是什么!


最简单的MIME信息
  这个信息没有任何段,也就是,没有附件。然而,因为它是一个MIME消息,它必须有必要的头。


From: php@php.net
To: 'Alex (the Great)' <alex@greece.net>
Subject: Bucephalus
MIME-Version: 1.0

Hello Alexander,

How's Bucephalus doing?

  这里面没有什么,它只是一个简单的拥有MIME头的符合RFC-822 的信息(文本邮件)。注意,如果没有
指定Content-Type头,则假设为Content-Type: text/plain;charset='us-ascii'!当然,它有些简单,复杂
一些的如下:


From: 'Alex (the Great)' <alex@greece.net>
To: php@php.net
Subject: re: Bucephalus
MIME-Version: 1.0
Content-Type: image/jpg;
name='buce.jpg'
Content-Transfer-Encoding: base64
Content-Description: Take a look at him yourself

<.....base64 encoded jpg image of Bucephalus...>

  "嗨,但是我想发送一个word文档和一张我的小狗的图片在同一封邮件中... !"一个用户说!如果是真
的,上面的那个例子就太简单了,并且它没有足够的内容来支持爱好者和现代邮件处理方面的需要。实际上,
许多的邮件客户端软件甚至不能显示描述字段!

  这就是我们所面临的"多部分信息"。


多部分信息(Multipart Messages)
  这个概念允许在一封邮件中发送多条项目。例如,假设Alexander想要给php@php.net发送一封他的马的
照片的邮件,同时还附带有马的家族图谱及精彩的说明!这样一个简单的要求没有多部分消息的概念是无法
被满足的。在这种情况下,我们创建了一个使用Content-Type的信息头的封装来支持邮件的不同部分,以便
收信人得到图片,家族图谱和精彩的说明!

  Content-Type 头现在拥有一个"multipart"的值,它表示这是一个完整的邮件信息并且这个头只封装了
信息。而且它还有一个"mixed"的子类型(毕竟图片,家族图谱和7bit文本信息是不同的类型,对吗?)。

  让我们看一下整个图片看上去象:


From: 'Alex (the Great)' <alex@greece.net>
To: php@php.net
Subject: re: Bucephalus
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="XX-1234DED00099A";
Content-Transfer-Encoding: 7bit

This is a MIME Encoded Message

--XX-1234DED00099A
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi PHP,

Attached you will find my horse, Bucephalus', pedigree chart and photo.

Alex

--XX-1234DED00099A
Content-Type: image/jpg;
name="buce.jpg";
Content-Transfer-Encoding: base64
Content-Description: "A photo of Bucephalus"

<.....base64 encoded jpg image of Bucephalus...>

--XX-1234DED00099A
Content-Type: application/octet-stream;
name="pedigree.doc"
Content-Transfer-Encoding: base64
Content-Description: "Pedigree Chart of the great horse"

<.....base64 encoded doc (pedigree.doc) of Bucephalus...>

--XX-1234DED00099A--

  哟,看上去很复杂,不是吗?不管怎样,让我们浏览一遍细节吧:

如果你注意到了在MIME信息头中的Content-Transfer-Encoding,为"7bit"。因为Content-Type为
multipart/mixed,编码应该是7bit,8bit或二进制中的一种,7bit是一种广泛使用的格式。
象这样一条信息包含了多种信息。客户程序是如何知道JPG图片,文档和普通文本之间的区别呢?你会
注意到在Content-Type后面有一个boundary="XX-1234DED00099A"参数。这个值用来分离邮件中的不同
部分。它叫做MIME边界标记。边界标记的值必须尽可能的唯一,以免在超出邮件范围时发生混乱。
"警告"信息(译者:指"This is a MIME Encoded Message")在那里是为了让不符合MIME的客户程序
能够把它显示给用户,否则他们就不理解一个空白邮件是什么意思。
现在,回到边界标记。如果你观察这个简单的邮件,会发现边界标记(XX-1234DED00099A在每一个分
都出现了,也就是,在每部分之间都使用了一个边界标记,然而,每个边界标记都以两个连接符开始。
很重要的一点需要注意的就是在最后一个MIME段的后面,边界标记不仅仅以那两个边接符作为开始,
同时也以它俩作为结束。这一点一定不能忘记,因为它定义了邮件的范围。
让我们看一下前两个MIME段:
第一段是普通文本信息,因此Content-Type为text/plain,并且编码为7bit(我们也可以省略它,
因为如果不指明它也会默认为如此)。
第二个就是JPEG图片。相应的表示为Content-Type: image/jpg。name="buce.jpg"(出现在
Content-Type的后面,称之为参数),指出了文件的名字;它就是可以在客户程序中看到的附件
的名字。如果不给出name="buce.jpg" ,描述字段(如果给出)将作为附件的名字显示出来(然
而,在所有客户程序中它不是统一的做法)。
注意JPEG 图片可以在邮件件中被显示出来,如果客户程序可以显示行内附件。或者,你可以向客户程
指明你想如何显示附件。例如,如果存在

Content-Disposition: attachment

头,JPEG图片将被显示为一个附件图标。

上一页 下一页


转自phpbuilder.com



用PHP发送MIME邮件(三)
译者:limodou 2000年8月14日

把它EMAIL给我 我来谈谈我的看法 上一篇 下一篇



作者:Kartic Krishnamurthy 译者:limodou

MIME 类
  在有了这些基础之后,让我们用PHP创建和实现一个MIME邮件类。在我们的PHP库函数中,已经有了编码
所必须的工具。

  MIME类必须能够:

增加附件
对每一个独立的请求,对所附的数据进行编码
创建MIME段/头
生成一个包含MIME段/头的完整的邮件
将整个邮件作为字符串返回
用本地的邮件处理程序进行发送(或选择调用一个SMTP邮件处理程序)
  这个类叫做MIME_mail。我们将讨论类的方法,在理论与实际的差距中建立起桥梁。(阅读建议:Luis
Argerich的PHP的面向对象编程:开发大型PHP项目的方法)。为了便于阅读大部分的注释已经被去掉了。一
些方法与类的成员变量只是用于内部处理,并且已经在下面的注释中被指出来了(同时在初始的类文件中也
指出了)。

------------------------------------
以下省略。。。。。。。。。。。。。。转自phpuser.com

直接定义一个含tag的html 摸板文件,把你的信息替换固定的 tag。然后 按base64编码,
发送就行了。 我觉得indy ics等mail client 应该支持 MIME 方式编码。也许不用这么
麻烦。
 
to:Linux2002
我试过了,为什么收到的是乱码?
 
idMessage.ContentType:='text/html, charset=gb2312'
坦克說得有
 
三代坦克说的是*.eml文件的格式
但是内部的Base64编码和解码,没有交待

unit mimecode;

// ?? : 拦蝴в (DWJ)
// E-Mail Address : u8106117@cseserv.cse.ttit.edu.tw

interface

procedure base64d(infile : string; outfile : string);
procedure base64e(infile : string; outfile : string);
procedure qpd( infile: string; outfile : string );
procedure qpe( infile:string; outfile:string );

implementation

uses
SysUtils;

(*---- Decoder ----*)
procedure base64d(infile : string; outfile : string);

var infp, outfp : TEXT;
in1, in2, in3, in4, t : char;
v1, v2, v3, v4 : integer;
out1, out2, out3 : char;
index, final : integer;

function ct(inchar : char) : integer;
begin
case inchar of
'A' : ct := 0 ; 'B' : ct := 1 ; 'C' : ct := 2 ; 'D' : ct := 3 ;
'E' : ct := 4 ; 'F' : ct := 5 ; 'G' : ct := 6 ; 'H' : ct := 7 ;
'I' : ct := 8 ; 'J' : ct := 9 ; 'K' : ct := 10 ; 'L' : ct := 11 ;
'M' : ct := 12 ; 'N' : ct := 13 ; 'O' : ct := 14 ; 'P' : ct := 15 ;
'Q' : ct := 16 ; 'R' : ct := 17 ; 'S' : ct := 18 ; 'T' : ct := 19 ;
'U' : ct := 20 ; 'V' : ct := 21 ; 'W' : ct := 22 ; 'X' : ct := 23 ;
'Y' : ct := 24 ; 'Z' : ct := 25 ; 'a' : ct := 26 ; 'b' : ct := 27 ;
'c' : ct := 28 ; 'd' : ct := 29 ; 'e' : ct := 30 ; 'f' : ct := 31 ;
'g' : ct := 32 ; 'h' : ct := 33 ; 'i' : ct := 34 ; 'j' : ct := 35 ;
'k' : ct := 36 ; 'l' : ct := 37 ; 'm' : ct := 38 ; 'n' : ct := 39 ;
'o' : ct := 40 ; 'p' : ct := 41 ; 'q' : ct := 42 ; 'r' : ct := 43 ;
's' : ct := 44 ; 't' : ct := 45 ; 'u' : ct := 46 ; 'v' : ct := 47 ;
'w' : ct := 48 ; 'x' : ct := 49 ; 'y' : ct := 50 ; 'z' : ct := 51 ;
'0' : ct := 52 ; '1' : ct := 53 ; '2' : ct := 54 ; '3' : ct := 55 ;
'4' : ct := 56 ; '5' : ct := 57 ; '6' : ct := 58 ; '7' : ct := 59 ;
'8' : ct := 60 ; '9' : ct := 61 ; '+' : ct := 62 ; '/' : ct := 63 ;
end;
end;

begin
try
Assign(infp,infile);
Assign(outfp,outfile);
Reset(infp);
Rewrite(outfp);

while not eof(infp) do
begin
read(infp,in1);
read(infp,in2);
read(infp,in3);
read(infp,in4);
if eoln(infp) then
begin
read(infp,t);
read(infp,t);
end;

v1 := ct(in1);
v2 := ct(in2);
v3 := ct(in3);
v4 := ct(in4);

if ((in3 = '=') and (in4 = '=')) then
begin
out1 := chr((v1 shl 2)+(v2 shr 4));
write(outfp,out1);
Close(infp);
Close(outfp);
Exit;
end
else if ((in3 <> '=') and (in4 = '=')) then
begin
out1 := chr((v1 shl 2)+(v2 shr 4));
out2 := chr((v2 shl 4)+(v3 shr 2));
write(outfp,out1);
write(outfp,out2);
Close(infp);
Close(outfp);
Exit;
end
else
begin
out1 := chr((v1 shl 2)+(v2 shr 4));
out2 := chr((v2 shl 4)+(v3 shr 2));
out3 := chr((v3 shl 6)+v4);
write(outfp,out1);
write(outfp,out2);
write(outfp,out3);
end;
end;
finally
close(outfp);
close(infp);
end;
end;

(*---- Encoder ----*)
procedure base64e(infile : string; outfile : string);

var infp, outfp : TEXT;
f : File of BYTE;
fsize,nsize : longInt;
in1, in2, in3, t : char;
out1, out2, out3, out4 : integer;
index, final : integer;

function ct(inchar : integer) : char;
begin
case inchar of
0 : ct := 'A' ; 1 : ct := 'B' ; 2 : ct := 'C' ; 3 : ct := 'D' ;
4 : ct := 'E' ; 5 : ct := 'F' ; 6 : ct := 'G' ; 7 : ct := 'H' ;
8 : ct := 'I' ; 9 : ct := 'J' ; 10 : ct := 'K' ; 11 : ct := 'L' ;
12 : ct := 'M' ; 13 : ct := 'N' ; 14 : ct := 'O' ; 15 : ct := 'P' ;
16 : ct := 'Q' ; 17 : ct := 'R' ; 18 : ct := 'S' ; 19 : ct := 'T' ;
20 : ct := 'U' ; 21 : ct := 'V' ; 22 : ct := 'W' ; 23 : ct := 'X' ;
24 : ct := 'Y' ; 25 : ct := 'Z' ; 26 : ct := 'a' ; 27 : ct := 'b' ;
28 : ct := 'c' ; 29 : ct := 'd' ; 30 : ct := 'e' ; 31 : ct := 'f' ;
32 : ct := 'g' ; 33 : ct := 'h' ; 34 : ct := 'i' ; 35 : ct := 'j' ;
36 : ct := 'k' ; 37 : ct := 'l' ; 38 : ct := 'm' ; 39 : ct := 'n' ;
40 : ct := 'o' ; 41 : ct := 'p' ; 42 : ct := 'q' ; 43 : ct := 'r' ;
44 : ct := 's' ; 45 : ct := 't' ; 46 : ct := 'u' ; 47 : ct := 'v' ;
48 : ct := 'w' ; 49 : ct := 'x' ; 50 : ct := 'y' ; 51 : ct := 'z' ;
52 : ct := '0' ; 53 : ct := '1' ; 54 : ct := '2' ; 55 : ct := '3' ;
56 : ct := '4' ; 57 : ct := '5' ; 58 : ct := '6' ; 59 : ct := '7' ;
60 : ct := '8' ; 61 : ct := '9' ; 62 : ct := '+' ; 63 : ct := '/' ;
end;
end;

begin
try
Assign(f, infile);
Reset(f);
fsize := Filesize(f);
finally
Close(f);
end;

try
Assign(infp,infile);
Assign(outfp,outfile);
Reset(infp);
Rewrite(outfp);
nsize := 0;
index := 0;

while (nsize < fsize) do
begin
inc(nsize);
read(infp,in1);
final := 8;
if (nsize < fsize) then
begin
inc(nsize);
read(infp,in2);
final := 16;
end
else in2 := chr(0);

if (nsize < fsize) then
begin
inc(nsize);
read(infp,in3);
final := 24;
end
else in3 := chr(0);

out1 := ord(in1) shr 2;
out2 := ((ord(in1) and 3) shl 4) + (ord(in2) shr 4);
out3 := ((ord(in2) and 15) shl 2) + ((ord(in3) and 192) shr 6);
out4 := ord(in3) and 63;

t := ct(out1);
inc(index);
write(outfp,t);

t := ct(out2);
inc(index);
write(outfp,t);

if ((final = 8) and (nsize = fsize)) then
begin
writeln(outfp,'==');
close(outfp);
exit;
end;
t := ct(out3);
inc(index);
write(outfp,t);

if ((final = 16) and (nsize = fsize)) then
begin
writeln(outfp,'=');
close(outfp);
close(infp);
exit;
end;

t := ct(out4);
inc(index);
write(outfp,t);
if index = 72 then
begin
writeln(outfp,'');
index := 0;
end;

end;

finally
close(outfp);
close(infp);
end;
end;

(*---- Encoder ----*)
procedure qpe( infile:string; outfile:string );
const keep = [#33..#60, #62..#126, #9, ' '];
var
f : file of byte;
infp, outfp : Text;
inchar : char;
oc1, oc2 : char;
len, icv, ocv1, ocv2 : integer;
fsize, nsize : longint;
begin
try
Assign( f, infile );
Reset( f );
fsize := Filesize( f );
nsize := 0;
finally
Close( f );
end;

try
Assign( infp, infile );
Assign( outfp, outfile );
Reset( infp );
Rewrite( outfp );
len := 0;

while ( nsize < fsize ) do
begin
read( infp, inchar );
inc( nsize );

if ( inchar = #13 ) then
begin
read( infp, inchar );
inc( nsize );
if ( inchar = #10 ) then
begin
writeln( outfp, '' );
len := 0;
end
else
begin
write( outfp, '=0D' );
len := len + 3;
if ( len > 70 ) then
begin
writeln( outfp, '=' );
len := 0;
end;

icv := ord( inchar );
ocv1 := icv DIV 16;
ocv2 := icv MOD 16;
if ocv1 < 10 then
oc1 := chr( ord( '0' ) + ocv1 )
else
oc1 := chr( ord( 'A' ) + ocv1 - 10 );

if ocv2 < 10 then
oc2 := chr( ord( '0' ) + ocv2 )
else
oc2 := chr( ord( 'A' ) + ocv2 - 10 );

write( outfp, '=', oc1, oc2 );
len := len + 3;
if ( len > 70 ) then
begin
writeln( outfp, '=' );
len := 0;
end;
end;
end
else
begin
if inchar in keep then
begin
write( outfp, inchar );
inc(len);
if ( len > 70 ) then
begin
writeln( outfp, '=' );
len := 0;
end;
end
else
begin
icv := ord( inchar );
ocv1 := icv DIV 16;
ocv2 := icv MOD 16;
if ocv1 < 10 then
oc1 := chr( ord( '0' ) + ocv1 )
else
oc1 := chr( ord( 'A' ) + ocv1 - 10 );

if ocv2 < 10 then
oc2 := chr( ord( '0' ) + ocv2 )
else
oc2 := chr( ord( 'A' ) + ocv2 - 10 );

write( outfp, '=', oc1, oc2 );
len := len + 3;
if ( len > 70 ) then
begin
writeln( outfp, '=' );
len := 0;
end;
end;
end;
end;
finally
Close( infp );
Close( outfp );
end;
end;

(*---- Decoder ----*)
procedure qpd( infile: string; outfile : string );
var infp, outfp : TEXT;
inchar : char;
line : string;
cl : boolean;
i1, i2 : integer;

procedure getnum( const c1 : char; const c2 : char );
var outchar : char;
t1, t2, t3, code : integer;
begin
t1 := 0;
t2 := 0;
t3 := 0;
outchar := ' ';

if ( c1 in ['0'..'9'] ) then
begin
val( c1, t1, code );
t1:= t1*16;
end
else if ( c1 in ['A'..'F'] ) then
begin
t1 := ( ord( c1 ) - ord( 'A' ) + 10 ) * 16;
end;

if ( c2 in ['0'..'9'] ) then
val(c2,t2,code)
else if ( c2 in ['A'..'F'] ) then
t2 := ( ord( c2 ) - ord( 'A' ) + 10 );

t3 := t1 + t2;
outchar := chr( t3 );
write( outfp, outchar );
end;

begin
try
inchar := ' ';
cl := false;
Assign( infp, infile );
Assign( outfp, outfile );
Reset( infp );
Rewrite( outfp );
while not eof( infp ) do
begin
readln( infp, line );
i2 := length( line );
if i2=0 then
begin
writeln( outfp, '' );
continue;
end;

cl := false;

if ( line[i2] <> '=' ) then
cl := true;
if line[i2] = '=' then
begin
delete( line, i2, 1 );
i2 := i2-1;
end;

i1 := 1;
while i1 <= i2 do
begin
if line[i1] = '=' then
begin
getnum( line[i1+1], line[i1+2] );
i1 := i1 + 2;
end
else write( outfp, line[i1] );
inc( i1 );
end;
if cl = true then
writeln( outfp, '' );
end;

finally
Close( infp );
Close( outfp );
end;
end;

end.
 
delphi 6 INDY 自己带了 base64编码控件.
 
此问题我已经解决,非常简单,用来根据公司客户数据库中的联系信息给他们发新产品信息,邮件正文就是HTML格式,看起来很彩色。
办法就是使用outlook automation,很小一个程序,如果你要,给我邮件地址吧。我还写了个附带的说明书,给国内的朋友用。
 
好啊,
1stgo@21cn.com
 
TSCL_moqing@163.com
Thinkers!
 
你用的邮件控件有个发送样式,将他设置为XXhtm(你自己去属性里找一下)。然后在你发送的正文里要包括<html>标记。(你的数据不会很复杂吧?)
 
顶部