Web Creation - еженедельный сетевой журнал для вебмастеров

   
 Почта на web-интерфейсе

Автор: Вадим Веденин

Данная статья раскрывает процесс организации web-интерфейса почтовой службы корпоративного интернет-сайта. Решение данной проблемы представляет из себя более сложную и интересную задачу, посмотрите пример ее реализации.

Для создания web-интерфейса имелись следующие ресурсы:

  1. Почтовый сервер на базе Unix
  2. Web сервер IIS 4.0 на базе NT Server 4.0
  3. MS SQL 7.0
Так как уже был создан почтовый сервер на базе Unix для домена, в котором находиться сайт нашей компании, то очевидно следующее решение задачи:
  1. необходима ActiveX-компонента, работающая по POP3 протоколу с почтовым сервером для приема писем с почтового ящика
  2. необходима ActiveX-компонента, работающая по SMTP протоколу для отсылки писем
  3. необходима ActiveX-компонента, загружающая файлы на Web-сервер для отсылки почты
Причем необходимое условие для этих компонент - их бесплатность.

Для приема почты я использовал компоненту JMAILс сайта http://tech.dimac.net/, для отправки почты и загрузки файлов - компоненты сайта http://www.dundas.com/. Также был использован файловый менеджер SA-filemanager http://www.softartisans.com/.

Популярную компоненту CDO я не использовал из-за того, что она работает только с почтовыми серверами, основанными на IIS.

Прием почты

Для соединения с POP сервером был использован следующий код:

Set pop3 = Server.CreateObject( "JMail.POP3" )
pop3.Connect login, pass, pop_server
где login, pass - соответствующие параметры почтового сервера Unix, pop_server - переменная, содержащая адрес почтового сервера.

Чтение заголовков сообщений осуществляется следующим образом:

Response.Write("папка Inbox: "& pop3.Count & " сообщений") 
Response.Write " <br>размер ящика " & pop3.Size & " байт "
		
i=1		
if pop3.count <> 0 then
	
Response.Write "<hr>"
	pop3.DownloadHeaders
	
pageCount=int(pop3.Count/pageSize)
	if pageCount=0 then pageCount=0 else
	if pageCount*pageSize<pop3.Count then pageCount=pageCount+1
		
	Response.Write	"<div align='center'>"		
	for i=1 to pageCount
Response.Write "<a href='pop.asp?curpage=" & i-1 & "'>" _
	& i & "</a> "
	next 
		
Response.Write "<br>"
Response.Write " страница " & curpage+1 & " из " & pageCount			
	
	Response.Write "</div>"
	%>  
	
<form method="post">
<table border="1" cellspacing="1" cellpadding="0" 
	bordercolor="DodgerBlue">
<tr bgcolor="DodgerBlue">
	<td> </td>
	<td> </td>
	
	<td align="center">от кого</td>
	<td align="center">получено</td>
	<td align="center">тема</td>
	
</tr>	
<%
for i=1 to pageSize
if curpage*pageSize+i>pop3.Count then exit for
%>	

<tr>
	
<td><input type="checkbox" name="checkDel" 
	value="<%=curpage*pageSize+i%>"></td>
<td align="center"><%if inStr(1,
	pop3.Messages.Item(curpage*pageSize+i).Charset,
	"iso-8859-1",1)<>0 then 
	Response.Write "<img src='image/attachment.gif' 
		width='13' height='14'>"%> 
	</td>
	
<td>
	<%Response.Write " " & pop3.Messages.item(curpage*pageSize+i).From %>
	</td>
	<td><%=pop3.Messages.item(curpage*pageSize+i).Date%></td>
	
<td>		
	<a href="read_message.asp?id=<%=curpage*pageSize+i%>">
	<%
  	select case Request.QueryString("kode")
	case "koi"
	Response.Write(koiTowin1251(pop3.Messages.item(curpage*pageSize+i).Subject)) 
 	case "win"
	Response.Write(pop3.Messages.item(curpage*pageSize+i).Subject) 
	case else
	if inStr(1,pop3.Messages.Item(curpage*pageSize+i).Charset,"koi8-r",1) <>0 
		or inStr(1,pop3.Messages.Item(curpage*pageSize+i).Charset,
			"iso-8859-1",1) <>0 then 
		Response.Write(koiTowin1251(
			pop3.Messages.item(curpage*pageSize+i).Subject)) 
	else
		Response.Write(pop3.Messages.item(curpage*pageSize+i).Subject) 
	end if	
	end select			
 	 
	%>
	</a>
	</td>
	
</tr>
<%
next 
%>
	
	</table>
	
	<input type="submit" value="удалить" name="delBut">
	</form>

И в конце страницы

<%
 pop3.Disconnect
 set pop3=Nothing
%>
При получении писем пришлось решать следующие проблемы: перекодировка сообщений, пришедших в кодировке KOI8-R, удаление сообщений, постраничное отображение полученных заголовков писем.

Проблема перекодировки сообщений возникает в случае, если сообщение приходит в кодировке koi8-r. Так как страница разработана в кодировке windows-1251, то вывод текста ссобщения без перекодировки привидет к тому что на странице будет текст в двух кодировках, что неприемлимо. Для этого создана функция перекодировки из koi8-r в windows-1251

function koiTowin1251(strkoi)

 dim winArray 
 dim koiArray 
 dim i 
 dim result 
 dim indexFind 
 
winArray="абвгдежзийклмнопрстуфхцчшщъыьэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"
 koiArray = "БВЧЗДЕЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАСвчздецъйклмнопртуфхжигюыэящшьас"
 
 for i=1 to len(strkoi)
   indexFind=instr(1,koiArray,mid(strkoi,i,1))
   if indexFind<>0 then
	result=result+mid(winArray,indexFind,1)
	else 
	 if mid(strkoi,i,1)=chr(13) then 
		i=i+1
		result=result+"<br>"
		else 
		result=result+mid(strkoi,i,1)
		end if				
   end if
  next 
 
 koiTowin1251=result
 end function 
Выбор между кодировками осуществляется при помощи передачи странице кода выбранной кодировки.

Для удаления сообщений достаточно использовать метод DeleteSingleMessage(id) компонеты JMail. Для этого необходимо следующее:

  1. при первом просмотре заголовков запомнить номер сообщения в тэге input <input type="checkbox" name="checkDel" value="<%=curpage*pageSize+i%>">
  2. при помощи кнопки submit передать это значение форме, содержащей серверный скрипт, удаляющий выбранное сообщение
Почтовое сообщение удаляется следующим скриптом:
if inStr(Request.ServerVariables("Request_Method"),
	"POST")<>0 then 

pop3.DownloadHeaders
for i=1 to  Request.Form("checkDel").Count
pop3.DeleteSingleMessage(int(Request.Form("checkDel")(i)))
next 
pop3.Disconnect
set pop3=Nothing
Response.Redirect "pop.asp"

End if
В данном скрипте проверяется , каким методом странице переданы параметры, и после этого сообщение удаляется.

Постраничное отображение полученных заголовков писем необходимо, если в почтовом ящике находится большое количество писем. Поэтому необходимо обеспечить отображение заголовков писем наборами по 10 штук ( например), и предоставить выбор нужного набора. Для этого странице передается параметр curpage в url старницы. Затем номер страницы инициализируется с помощью следующего кода

if len(Request.QueryString("curpage"))=0 then
 curpage = 0 
else
 curpage= CInt (Request.QueryString("curpage"))
 end if
Затем, на основе полученного значения и отображается выбранная страница. Выбор номера нужного набора сообщений я предоставляю следующим образом
pageCount=int(pop3.Count/pageSize)
if pageCount<>0 then 
if pageCount*pageSize<pop3.Count then pageCount=pageCount+1
	end if
		
Response.Write	"<div align='center'>"		
for i=1 to pageCount
 Response.Write "<a href='pop.asp?curpage=" _
 	& i-1 & "'>" & i & "</a>&nbsp;"
next 

Response.Write "<br>"
Response.Write " страница " & curpage+1 & " из " & pageCount			
Response.Write "</div>"

Чтение выбранного сообщения

При чтении сообщения возникает проблема кодировки, корректного отображения тела сообщения на asp странице, сохранения вложенных файлов на машину клиента.

Метод решения проблемы кодировки описан выше.

Проблема отображения заключается в следующем: в теле сообщения переход на новую строку указан комбинацией специальных символов "перевод каретки" и "переход строки", которые игнорируются броузером. Для этого надо заменить все вхождения данных симолов на тэг <br> то есть комбинацию chr(13)chr(10) на "<br>" для этого создана функция convertForHTML

function convertForHTML(str)
 dim result
 dim i
 result=""
 
 for i=1 to len(str)
	 if mid(str,i,1)=chr(13) then 
		i=i+1
		result=result+"<br>"
		else 
		result=result+mid(str,i,1)
	end if				
 next 
 convertForHTML=result
 end function
Для сохранения вложений на машину клиента я использовал примеры с сайта http://www.aspfaqs.com/demos/StreamBinaryDemo.asp, http://prosto.pp.ru/Menu/Menu.htm и файловый менеджер SA-FileManager. Пример сохранения вложений
<%@ Language=VBScript%>

<!-- #include file="include/general.asp"-->

<%

dim id
dim attach
dim oFM
dim oBS
dim id_att
dim item 
dim sbody
dim mess
dim i
on error resume next
login=Request.Cookies("login")
pass=Request.Cookies("pass")
fio=Request.Cookies("fio")

if len(login)= 0 and len(pass)=0 then Response.Redirect("index.asp")

Set pop3 = Server.CreateObject("JMail.POP3")

pop3.Connect login, pass, smtp_server 
id=Request.QueryString("id")
id_att=Request.QueryString("id_att")

pop3.DownloadMessages
Set oFM = CreateObject("SoftArtisans.FileManager")

set attach=pop3.Messages(id).Attachments.Item(int(id_att))
		
if 	oFM.FileExists(Server.MapPath("temp") _
	& "\" & attach.Name)=true then oFM.DeleteFile Server.MapPath("temp") _
	& "\" & attach.Name
attach.SaveToFile Server.MapPath("temp") & "\" & attach.Name
Set oBS = oFM.OpenBinaryFile(Server.MapPath("temp") & "\" & attach.Name)
	
Response.Addheader "Content-Disposition", "attachment; filename=" & attach.Name
Response.ContentType=attach.ContentType

sbody=oBS.readAll

Response.BinaryWrite(sbody)	
oBS.Close
oFM.DeleteFile Server.MapPath("temp") & "\" & attach.Name
set oBS=nothing

set attach=nothing
set sbody=nothing


set oFM=nothing
pop3.Disconnect
set pop3=Nothing		
set mess=nothing
		
if Err.number<> 0 then
%>
<!-- #include file="error.asp"-->		
<% end if
%>
Скрипт, осуществляющий чтение выбранного сообщения
<table bgcolor=Wheat align=center border="1" 
cellspacing="0" cellpadding="0" bordercolor=DodgerBlue width=90%>
<tr>
<td>тема</td>
<td>
<%
		 	
 select case Request.QueryString("kode")
 case "koi"
	Response.Write(koiTowin1251(pop3.Messages.item(id).Subject)) 
 case "win"
	Response.Write(pop3.Messages.item(id).Subject) 
 case else
 	if inStr(1,pop3.Messages.Item(id).Charset,"koi8-r",1) <>0 
 		or inStr(1,pop3.Messages.Item(id).Charset,"iso-8859-1",1) <>0 then 
		Response.Write(koiTowin1251(pop3.Messages.item(id).Subject)) 
	else
		Response.Write(pop3.Messages.item(id).Subject) 
	end if	
 end select			
	 	 
%>
</td>
</tr>
<tr>
<td>автор</td>
<td>ответить на <a 
href="send_message.asp?toAddress=
<%=pop3.Messages.Item(id).From%>"><%
if len(pop3.Messages.item(id).FromName) <> 0 then 	

if inStr(1,pop3.Messages.Item(id).Charset,"koi8-r",1) <>0 
	or inStr(1,pop3.Messages.Item(id).Charset,"iso-8859-1",1) <>0 then 
	Response.Write(koiTowin1251(pop3.Messages.item(id).FromName))
else

	 select case Request.QueryString("kode")
     case "koi"
		Response.Write(koiTowin1251(pop3.Messages.item(id).FromName)) 
  	 case "win"
		Response.Write(convertForHTML(pop3.Messages.item(id).FromName)) 
	 case else
	 	if inStr(1,pop3.Messages.Item(id).Charset,"koi8-r",1) <>0 
	 	or inStr(1,pop3.Messages.Item(id).Charset,"iso-8859-1",1) <>0 then 
			Response.Write(koiTowin1251(pop3.Messages.item(id).FromName)) 
		else
			Response.Write(convertForHTML(pop3.Messages.item(id).FromName)) 
		end if	
	 end select			
end if
else
	Response.Write " <" & pop3.Messages.item(id).From & ">" 
end if		

%></a></td>
</tr>
<%
if  pop3.Messages.Item(id).Attachments.Count <> 0 then 
%>
<tr>
<td>вложения</td>
	<td><%
	for i=0 to pop3.Messages.Item(id).Attachments.Count-1
	%>
	<a href="save_client.asp?id=<%=id%>&id_att=<%=i%>">
	<%			
		Response.Write pop3.Messages(id).Attachments.Item(i).Name _
		& " " & pop3.Messages.Item(id).Attachments.Item(i).Size _
		& " байт</a><br>"
	
	next
	%>
	
	<%'=" type " & pop3.Messages(id).Attachments.Item(0).ContentType%>
	</td>	
</tr>
<%
end if
%>
<tr>
<td valign="top"> сообщение </td>
<td valign="top">
		
<%
			 	
 select case Request.QueryString("kode")
 case "koi"
	Response.Write(koiTowin1251(pop3.Messages.item(id).Body)) 
 case "win"
	Response.Write(convertForHTML(pop3.Messages.item(id).Body)) 
 case else
 	if inStr(1,pop3.Messages.Item(id).Charset,"koi8-r",1) <>0 
 	or inStr(1,pop3.Messages.Item(id).Charset,"iso-8859-1",1) <>0 then 
		Response.Write(koiTowin1251(pop3.Messages.item(id).Body)) 
	else
		Response.Write(convertForHTML(pop3.Messages.item(id).Body)) 
	end if	
 end select			
		 	 
%>		
</td>
</tr>
</table>

Отправка сообщений

Для отправки сообщений использованы Mailer- и Upload- компонета с сайта http://www.dundas.com/.

Пример отправки сообщения с вложенным файлом

if inStr(Request.ServerVariables("Request_Method"),"POST")<>0 then 

Dim objMailer 'Mailer control   
Dim objUpload 
set  objUpload = Server.CreateObject("Dundas.Upload.2")
set objMailer = Server.CreateObject("Dundas.Mailer")

objUpload.UseUniqueNames=false
 objUpload.UseVirtualDir=true 
 objUpload.MaxUploadSize=maxUploadSize
 objUpload.Save "temp"
  
 ' послать

 objMailer.SMTPRelayServers.Add smtp_server 
 
' посылаем тело  письма
if objUpload.Files.count = 0 then 

objMailer.CustomHeaders.Add "Content-Type:", 
	"text/plain;charset=windows-1251" 

objMailer.TOs.Add objUpload.Form("to")
objMailer.Subject = objUpload.Form("subject")
objMailer.Body =  objUpload.Form("body")
objMailer.FromAddress = senderAddress
objMailer.FromName=senderName

else
' посылаем вложение

' Response.Write "<br>" & objUpload.Files.count
 if objUpload.Files.count <> 0 then 

objMailer.TOs.Add objUpload.Form("to")
objMailer.Subject = objUpload.Form("subject")
objMailer.FromAddress = senderAddress 
objMailer.FromName=senderName

For Each Item in objUpload.Files
  objMailer.Attachments.Add Item.Path,Item.OriginalPath,
  	Item.ContentType,"BASE64","windows-1251"
Next

objMailer.Body =  objUpload.Form("body")

set item=nothing
 	
 end if	
 end if	

 objMailer.SendMail
 Set objMailer = Nothing
 set objUpload=nothing
 send_ok=True
 end if
Таким образом, достаточно простой web- интерфейс для почты на сайте готов.

За рамками статьи я оставляю вопросы идентификации и регистрации пользователя, так как для этого использовались cookies и работы с БД, что достаточно просто. Адрес сайта, для которого была разработана данная система, не предоставляется, так как на момент написания статьи еще не была проведена работа по защите от несанкционированного доступа.

Автор: Вадим Веденин

 

© журнал принадлежит Web Creation
по всем вопросам обращаться А. Кузьмин