论坛: 黑客进阶 标题: 可否自动下载发件箱中的邮件? 复制本贴地址    
作者: cicada [cicada]    论坛用户   登录
可否自动下载发件箱中的邮件?

地主 发表时间: 06-05-29 17:03

回复: blackx [blackx]   论坛用户   登录
你的意思是下邮件还是下邮件里的附件程序哦,说清楚一点嘛。

B1层 发表时间: 06-06-01 10:53

回复: cicada [cicada]   论坛用户   登录
谢谢回复,我的意思是下发件箱里面的邮件,当然邮件中有附件的话也一起下载了,如果编程的话,如何实现呢?

B2层 发表时间: 06-06-01 14:44

回复: blackx [blackx]   论坛用户   登录
信箱是自己的的话需要用收发信工具收信应该能做到这一点哈,你如果是想在别人的信箱上面做手脚的话先把程序写成代码才行

B3层 发表时间: 06-06-15 03:27

回复: hcz [hcz]   论坛用户   登录
foxmail

B4层 发表时间: 06-06-15 09:40

回复: cicada [cicada]   论坛用户   登录
foxmail不能收取发信箱的信

B5层 发表时间: 06-06-15 10:33

回复: cicada [cicada]   论坛用户   登录
我有自己信箱的用户和密码,如何编程收取发信箱的信件呢?

B6层 发表时间: 06-06-15 10:35

回复: cicada [cicada]   论坛用户   登录
顶一下了!

B7层 发表时间: 06-06-26 09:06

回复: studentol [studentol]   论坛用户   登录
你首先要了解邮件的协议,然后有windows的api函数编写。linux也行

B8层 发表时间: 06-07-01 16:31

回复: cicada [cicada]   论坛用户   登录
能不能讲具体一点呢?

B9层 发表时间: 06-07-10 10:39

回复: studentol [studentol]   论坛用户   登录
好!!!!有摆渡大哥的 帮助,我就助你一次:
Attribute VB_Name = "Module1"
Public Const conMailLongDate = 0
Public Const conMailListView = 1
'标识取消发送的变量
Public SendWithApi
Public Const conOptionGeneral = 1
Public Const conOptionMessage = 2
Public Const conUnreadMessage = "*"
Public Const vbRecipTypeTo = 1
Public Const vbRecipTypeCc = 2
'定义当 MAPIMessages 控件被激活时,Action属性使用的常数
'该属性决定将执行什么操作
Public Const vbMessageFetch = 1
Public Const vbMessageSenddlg = 2
Public Const vbMessageSend = 3
Public Const vbMessageSaveMsg = 4
Public Const vbMessageCopy = 5
Public Const vbMessageCompose = 6
Public Const vbMessageReply = 7
Public Const vbMessageReplyAll = 8
Public Const vbMessageForward = 9
Public Const vbMessageDelete = 10
Public Const vbMessageShowADBook = 11
Public Const vbMessageShowDetails = 12
Public Const vbMessageResolveName = 13
Public Const vbRecipientDelete = 14
Public Const vbAttachmentDelete = 15
Public Const vbAttachTypeData = 0
Public Const vbAttachTypeEOLE = 1
Public Const vbAttachTypeSOLE = 2
'定义存储邮件信息的结构
Type ListDisplay
    Name As String * 20
    Subject As String * 40
    Date As String * 20
End Type
Public currentRCIndex As Integer
Public UnRead As Integer
Public SendWithMapi As Integer
Public ReturnRequest As Integer
Public OptionType As Integer
   
'声明读取注册表内容的函数
#If Win32 Then
Public Declare Function GetProfileString Lib "kernel32" Alias "GetProfileStringA" (ByVal lpAppName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long) As Long
#Else
Public Declare Function GetProfileString% Lib "kernel" Alias "GetProfileStringA" (ByVal lpAppName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long)
#End If

Public Sub Attachments(msg As Form)
'将有附件的信息装载到窗体msg的列表框alist中
msg.alist.Clear
msg.numAtt = "附加文件数量:" & VBMail.MAPIMess.AttachmentCount
If VBMail.MAPIMess.AttachmentCount Then
    For i% = 0 To VBMail.MAPIMess.AttachmentCount - 1
    VBMail.MAPIMess.AttachmentIndex = i%
    a$ = VBMail.MAPIMess.AttachmentName
    Select Case VBMail.MAPIMess.AttachmentType
        Case vbAttachTypeData
            a$ = a$ + "(Data File)"
        Case vbAttachTypeEOLE
            a$ = a$ + "(Embedded OLE Object)"
        Case vbAttachTypeSOLE
            a$ = a$ + "(Static OLEObject)"
        Case Else
            a$ = a$ + "(Unknown attachment type)"
    End Select
    msg.alist.AddItem a$
    Next i%
End If
msg.Refresh
End Sub

Public Sub CopyNamestoMsgBuffer(msg As Form, fResolveNames As Integer)
'删除原来的收信人地址
Call KillRecips(VBMail.MAPIMess)
'窗体msg中填写的收信人和抄送人地址添加到发送邮件的地址
Call SetRCList(msg.txtTo, VBMail.MAPIMess, vbRecipTypeTo, fResolveNames)
Call SetRCList(msg.txtCc, VBMail.MAPIMess, vbRecipTypeTo, fResolveNames)
End Sub

Public Function DateFromMapiDate$(ByVal S$, wFormat%)
'该函数的功能根据给定的日期,返回一定格式的日期的表示形式
Y$ = Left$(S$, 4)
M$ = Mid$(S$, 6, 2)
D$ = Mid$(S$, 9, 2)
T$ = Mid$(S$, 12)
Ds# = DateValue(M$ + "/" + D$ + "/" + Y$) + TimeValue(T$)
Select Case wFormat
    Case conMailLongDate
        f$ = "dddd,mmmm,d,yyyy,h:mmAM/PM"
    Case conMailListView
        f$ = "mm/dd/yy hh:mm"
End Select
DateFromMapiDate = Format$(Ds#, f$)
End Function

Public Sub DeleteMessage()
'该子程序的删除当前选中的邮件
If TypeOf Screen.ActiveForm Is MsgView Then
    MailLst.Mlist.ListIndex = Val(Screen.ActiveForm.Tag)
    ViewingMsg = ture
End If
If MailLst.Mlist.ListIndex <> -1 Then
    '如果消息索引不等与-1(不是在书写新信件),则删除当前消息
    VBMail.MAPIMess.MsgIndex = MailLst.Mlist.ListIndex
    VBMail.MAPIMess.Action = vbMessageDelete
    '从列表框中删除相应的消息
    x% = MailLst.Mlist.ListIndex
    MailLst.Mlist.RemoveItem x%
    If x% < MailLst.Mlist.ListCount - 1 Then
        MailLst.Mlist.ListIndex = x%
    Else
        MailLst.Mlist.ListIndex = MailLst.Mlist.ListCount - 1
    End If
    VBMail.Statusbar1.Panels(1) = "收信箱里共有" + Format$(VBMail.MAPIMess.MsgCount) + "邮件,其中有" + Format$(UnRead) + "未读"
    If ViewingMsg Then
        '删除当前活动窗体的消息后,将其标志设为-1
        Screen.ActiveForm.Tag = Str$(-1)
    End If
    For i = 0 To Forms.Count - 1
        If TypeOf Forms(i) Is MsgView Then
            If Val(Forms(i).ta) > x% Then
                '将阅读邮件的窗体的tag属性设为邮件的索引
                Forms(i).Tag = Val(Forms(i).Tag) - 1
            End If
        End If
    Next i
    If vewingmsg Then
        '在删除当前邮件后,下一封邮件的位置设置为当前位置,这时需要
        '判断该邮件是否已经在子窗体MsgView中显示,如是,将其设为活动
        '窗体,否则,用MsgView显示该邮件
        windowNum% = FindMsgWindow(MailLst.Mlist.ListIndex)
        If windowNum% > 0 Then
            If Forms(windowNum%).Caption <> Screen.ActiveForm.Caption Then
                Unload Screen.ActiveForm
                Forms(FindMsgWindow((MailLst.Mlist.ListIndex))).Show
            Else
                Forms(windowNum%).Show
            End If
        Else
            Call LoadMessage(MailLst.Mlist.ListIndex, Screen.ActiveForm)
        End If
    Else
        windowNum% = FindMsgWindow(x%)
        If windowNum% > 0 Then
          Unload Forms(x%)
        End If
    End If
End If
End Sub

Public Sub DisplayAttachedFile(ByVal FileName As String)
'该子程序用于根据文件的类型查看附件文件
On Error Resume Next
ext$ = FileName
junk$ = Token$(ext$, ".")
Buffer$ = String$(256, "")
errCode% = GetProfileString("Extensions", ext$, "NOTFOUND", Buffer$, Len(Left(Buffer$, Chr(0)) - 1))
If errCode% Then
    Buffer$ = Mid$(Buffer$, 1, InStr(Buffer$, Chr(0)) - 1)
    If Buffer$ <> "NOTFOUND" Then
        EXEName$ = Token$(Buffer$, "")
        errCode% = Shell(EXEName$ + "" + FileName, 1)
        If Err Then
            MsgBox "Error occurred during the shell:" + Error$
        End If
    Else
        MsgBox "Appliction that uses:<" + ext$ + ">not found in WIN.INI"
    End If
End If
End Sub

Public Function FindMsgWindow(Index As Integer) As Integer
'判断当前所有子窗体中是否包含有相对邮件索引的邮件
'如果没有则返回值为-1
For i = 0 To Forms.Count - 1
    If TypeOf Forms(i) Is MsgView Then
        If Val(Forms(i).Tag) = Index Then
            FindMsgWindow = i
            Exit Function
        End If
    End If
Next i
FindMsgWindow = -1
End Function

Public Function GetHeader(msg As Control)
'从MAPIMessages控件取得邮件的头信息
Dim CR As String
CR = Chr$(13) + Chr$(10)
Header$ = String$(25, "-")
Header$ = Header$ + "From:" + msg.MsgOrigDisplayName + CR
Header$ = Header$ + "To:" + GetRCList(msg, vbRecipTypeTo) + CR
Header$ = Header$ + "Cc:" + GetRCList(msg, vbRecipTypeCc) + CR
Header$ = Header$ + "Subject:" + msg.MsgSubject + CR
Header$ = Header$ + "Date:" + _
DateFromMapiDate$(msg.MsgDateReceived, conMailLongDate) + CR + CR
GetHeader = Header$
End Function

Public Sub GetMessageCount()
'获得邮箱中所有消息(邮件)的数量
Screen.MousePointer = 11
VBMail.MAPIMess.FetchUnreadOnly = 0
VBMail.MAPIMess.Action = vbMessageFetch
VBMail.Statusbar1.Panels(1) = "收信箱里共有" + Format$(VBMail.MAPIMess.MsgCount) + "邮件"
Screen.MousePointer = 0
End Sub

Public Function GetRCList(msg As Control, RCType As Integer) As String
'从MAPIMessages控件中获得所有收信人的姓名,
'姓名之间用分号隔开,返回值为所有收信人姓名
For i = 0 To msg.RecipCount - 1
    msg.RecipIndex = i
    If RCType = msg.RecipType Then
        a$ = a$ + ";" + msg.RecipDisplayName
    End If
Next i
If a$ <> "" Then
    a$ = Mid$(a$, 2)
End If
GetRCList = a$
End Function

Public Sub KillRecips(Msgcontrol As Control)
'从MAPIMessages控件中删除所有收信人地址
While Msgcontrol.RecipCount
    Msgcontrol.Action = vbRecipientDelete
Wend
End Sub

Public Sub LoadList(mailctl As Control)
'将邮件的信息装载到邮件列表窗体中的列表框
MailLst.Mlist.Clear
UnRead = 0
startindex = 0
For i = 0 To mailctl.MsgCount - 1
    mailctl.MsgIndex = i
    If Not mailctl.MsgRead Then
        '在尚未阅读过的邮件之前用“*”表示(conUnreadMessage="*")
        a$ = conUnreadMessage + ""
        If UnRead = 0 Then
            '标识第一封没有阅读过的邮件的位置
            startindex = i
        End If
        'UnRead为计算没有阅读过的邮件的数量
        UnRead = UnRead + 1
    Else
        a$ = " "
    End If
    '取得当前索引消息的原始发件人的名字
    a$ = a$ + Mid$(Format$(mailctl.MsgOrigDisplayName, "!" + String$(10, "@")), 1, 10)
    If mailctl.MsgSubject <> "" Then
        '取得当前索引消息的主题
        b$ = Mid$(Format$(mailctl.MsgSubject, "!" + String$(35, "@")), 1, 35)
    Else
        b$ = String$(30, "")
    End If
    '取得当前消息的接收时间
    c$ = Mid$(Format$(DateFromMapiDate(mailctl.MsgDateReceived, conMailListView), "!" + String$(15, "@")), 1, 15)
    '将消息的头信息添加到列表框中
    MailLst.Mlist.AddItem a$ + Chr$(9) + b$ + Chr$(9) + c$
    MailLst.Mlist.Refresh
Next i
'消息列表框的索引在第一条没有阅读的消息的位置
MailLst.Mlist.ListIndex = startindex
VBMail.Toolbar1.Buttons("Next1").Enabled = True
VBMail.Toolbar1.Buttons("Previous1").Enabled = True
VBMail.Toolbar1.Buttons("Delete").Enabled = True
If UnRead Then
    '在状态栏中显示没有阅读的消息的数量
    VBMail.Statusbar1.Panels(1) = "收信箱里共有" + Format$(VBMail.MAPIMess.MsgCount) + "邮件,其中有" + Format$(UnRead) + "未读"
Else
    VBMail.Statusbar1.Panels(1) = ""
End If
End Sub
Sub LoadMessage(ByVal Index As Integer, msg As Form)
'将当前消息(根据Index)装载到窗体msg中
'msg窗体可以是查看消息的窗体MsgView,
'也可以是书写新消息的窗体NewMsg
If TypeOf msg Is MsgView Then
    '如果装载消息到查看消息的窗体,则根据该消息是否
    '被阅读来清楚消息未读的标志“*”
    a$ = MailLst.Mlist.List(Index)
    If Mid$(a$, 1, 1) = conUnreadMessage Then
        Mid$(a$, 1, 1) = ""
        MailLst.Mlist.List(Index) = a$
        UnRead = UnRead - 1
        If UnRead Then
            '阅读的是新消息,则未读消息的数量-1
            VBMail.Statusbar1.Panels(1) = "收信箱里共有" + Format$(VBMail.MAPIMess.MsgCount) + "邮件,其中有" + Format$(UnRead) + "未读"
        Else
            VBMail.Statusbar1.Panels(1) = "收信箱里共有" + Format$(VBMail.MAPIMess.MsgCount) + "邮件,其中有" + Format$(UnRead) + "未读"
        End If
    End If
End If
If TypeOf msg Is MsgView Then
'如果装载消息到查看消息的窗体,则取得消息的日期和发信人
    VBMail.MAPIMess.MsgIndex = Index
    msg.txtDate.Text = "日期:" + DateFromMapiDate$(VBMail.MAPIMess.MsgDateReceived, conMailLongDate)
    msg.txtFrom.Text = "发信人:" + VBMail.MAPIMess.MsgOrigDisplayName
    MailLst.Mlist.ItemData(Index) = True
End If
'不管消息装载到哪个窗体中,均执行以下程序
Call Attachments(msg)
msg.txtNoteText.Text = "邮件" + Chr$(13) + Chr$(10) + VBMail.MAPIMess.MsgNoteText
msg.txtSubject.Text = "主题:" + VBMail.MAPIMess.MsgSubject
msg.Caption = VBMail.MAPIMess.MsgSubject
msg.Tag = Index
msg.txtTo.Text = "收信人:" + GetRCList(VBMail.MAPIMess, vbRecipTypeTo)
msg.txtCc.Text = "抄送:" + GetRCList(VBMail.MAPIMess, vbRecipTypeCc)
msg.Refresh
msg.Show
End Sub
Sub LogOffUser()
'该子程序用于注销发送邮件连接
On Error Resume Next
VBMail.MAPISess.Action = 2
If Err <> 0 Then
    MsgBox "LogOff failure:" + Error
Else
    VBMail.MAPIMess.SessionID = 0
    VBMail.Logoff.Enabled = 0
    VBMail.Logon.Enabled = -1
    '卸载所有的子窗体
    Do Until Forms.Count = 1
        i = Forms.Count - 1
        If TypeOf Forms(i) Is MDIForm Then
        Else
            Unload Forms(i)
        End If
    Loop
    '设置各个菜单项及工具栏按扭的可用状态
    VBMail.Toolbar1.Buttons("Compose").Enabled = False
    VBMail.Toolbar1.Buttons("Fetch").Enabled = False
    VBMail.Toolbar1.Buttons("Previous1").Enabled = False
    VBMail.Toolbar1.Buttons("Next1").Enabled = False
    VBMail.Toolbar1.Buttons("Delete").Enabled = False
    VBMail.Toolbar1.Buttons("Send").Enabled = False
    VBMail.Toolbar1.Buttons("Reply").Enabled = False
    VBMail.Toolbar1.Buttons("ReplyAll").Enabled = False
    VBMail.Toolbar1.Buttons("Forward").Enabled = False
    VBMail.ShowAB.Enabled = False
    VBMail.EditDelete.Enabled = False
    VBMail.Mforward.Enabled = False
    VBMail.Mreply.Enabled = False
    VBMail.Mreplyall.Enabled = False
    VBMail.Mcompose.Enabled = False
    VBMail.Mfetch.Enabled = False
    VBMail.PrintMessage.Enabled = False
    VBMail.EditDelete.Enabled = False
    VBMail.Statusbar1.Panels(1) = "现处于离线状态"
    VBMail.Statusbar1.Panels(2) = ""
End If
End Sub
Sub PrintLongText(ByVal LongText As String)
'打印消息的子程序之一,用于打印消息的正文
Do Until LongText = ""
    word$ = Token$(LongText, "")
    If Printer.TextHeight(word$) + Printer.CurrentX > Printer.Width - Printer.TextWidth("ZZZZZZZ") Then
        Printer.Print
    End If
    Printer.Print "" + word$
Loop
End Sub
Sub Printmail()
'打印消息的子程序之一,用于取得要打印的消息
If TypeOf Screen.ActiveForm Is MsgView Then
    '如果当前活动的子窗体为MsgView,则打印相应的邮件消息
    Call PrintMessage(VBMail.MAPIMess, False)
    Printer.EndDoc
ElseIf TypeOf Screen.ActiveForm Is MailLst Then
    For i = 0 To MailLst.Mlist.ListCount - 1
        If MailLst.Mlist.Selected(i) Then
            '如果活动的子窗体是邮件消息列表,则根据列表框中的索引打印
            '相应的消息
            VBMail.MAPIMess.MsgIndex = i
            Call PrintMessage(VBMail.MAPIMess, False)
        End If
    Next i
    Printer.EndDoc
End If
End Sub
Sub PrintMessage(msg As Control, fNewPage As Integer)
'打印消息的子程序之一,用于设置打印机和取得打印消息头
Screen.MousePointer = 11
If fNewPage Then
    Printer.NewPage
End If
Printer.FontName = "Arial"
Printer.FontBold = True
Printer.DrawWidth = 10
Printer.Line (0, Printer.CurrentY)-(Printer.Width, Printer.CurrentY)
Printer.Print
Printer.FontSize = 9.75
Printer.Print "From:"
Printer.CurrentX = Printer.TextWidth(String$(30, ""))
Printer.Print msg.MsgOrigDisplayName
Printer.Print "To:"
Printer.CurrentX = Printer.TextWidth(String$(30, ""))
Printe.Print GetRCList(msg, vbRecipTypeTo)
Printer.Print "Cc:"
Printer.CurrentX = Printer.TextWidth(String$(30, ""))
Printer.Print GetRCList(msg, vbRecipTypeCc)
Printer.Print "Subject:"
Printer.CurrentX = Printer.TextWidth(String$(30, ""))
Printer.Print msg.MsgSubject
Printer.Print "Date:"
Printer.CurrentX = Printer.TextWidth(String$(30, ""))
Printer.Print DateFromMapiDate$(msg.MsgDateReceived, conMailLongDate)
Printer.Print
Printer.DrawWidth = 5
Printer.Line (0, Printer.CurrentY)-(Printer.Width, Printer.CurrentY)
Printer.FontSize = 9.75
Printer.FontBold = False
Call PrintLongText(msg.MsgNoteText)
Printer.Print
Screen.MousePointer = 0
End Sub

Sub SaveMessage(msg As Form)
'???该子程序的调用在何处?????
svSub = msg.txtSubject
svNote = msg.txtNoteText
VBMail.MAPIMess.Action = vbMessageCopy
VBMail.MAPIMess.MsgSubject = svSub
VBMail.MAPIMess.MsgNoteText = svNote
VBMail.MAPIMess.Action = vbMessageSaveMsg
End Sub

Sub SetRCList(ByVal NameList As String, msg As Control, RCType As Integer, fResolveNames As Integer)
'根据存储收信人姓名的字符串NameList(姓名用分号隔开)
'设置收信人姓名。
If NameList = "" Then
    Exit Sub
End If
i = msg.RecipCount
Do
    msg.RecipIndex = i
    msg.RecipDisplayName = Trim$(Token(NameList, ";"))
    If fresolvename Then
        msg.Action = vbMessageResolveName
    End If
    msg.RecipType = RCType
    i = i + 1
Loop Until (NameList = "")
End Sub

Function Token$(tmp$, search$)
x = InStr(1, tmp$, search$)
If x Then
  Token$ = Mid$(tmp$, 1, x - 1)
  tmp$ = Mid$(tmp$, x + 1)
Else
  Token$ = tmp$
  tmp$ = ""
End If
End Function

Sub UpdateRecips(msg As Form)
'更新收信人和转发的地址
msg.txtTo.Text = GetRCList(VBMail.MAPIMess, vbRecipTypeTo)
msg.txtCc.Text = GetRCList(VBMail.MAPIMess, vbRecipTypeCc)
End Sub

Sub ViewNextMsg()
'查看下一个消息
windowNum% = FindMsgWindow(MailLst.Mlist.ListIndex)
If windowNum% > 0 Then
    Forms(windowNum%).Show
Else
    If TypeOf Screen.ActiveForm Is MsgView Then
        Call LoadMessage(MailLst.Mlist.ListIndex, Screen.ActiveForm)
    Else
        Call LoadMessage(MailLst.Mlist.ListIndex, MsgView)
    End If
End If
End Sub
(全部代码加我qq后给你"因为我的空间坏了")

B10层 发表时间: 06-07-12 17:59

回复: cicada [cicada]   论坛用户   登录
研究ing,谢谢!

B11层 发表时间: 06-07-17 07:59

回复: xiean [xiean]   论坛用户   登录
好像 POP3 是没法直接收取发件箱(.Sent)里的邮件的,IMAP 可以

没有详细研究这个问题,有错的话欢迎指出

B12层 发表时间: 06-07-23 14:26

回复: xiaoshi [xiaoshi]   论坛用户   登录
很早以前看过的,按上面的操作可以收发163的信,好像附件不行,记不清楚怎么做了,有时间看看

用c#写的smtp邮件发送类 
//**********************Created by Chen**************************
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Collections.Specialized;
using KSN.Exceptions;
using KSN.Validate;
namespace KSN.Web.Mail
{
/// <summary>
/// 邮件内容
/// </summary>
public class MailMessage
{
  private string sender=null;
  private StringCollection receivers=new StringCollection();
  private string subject="";
  private string xMailer="";
  private StringCollection attachments=new StringCollection();
  private MailEncodings mailEncoding=MailEncodings.GB2312;
  private MailTypes mailType=MailTypes.Html;
  private byte[] mailBody=null;
  /// <summary>
  /// 获取或设置发件人
  /// </summary>
  public string Sender
  {
  get{return this.sender;}
  set{this.sender=value;}
  }
  /// <summary>
  /// 获取收件人地址集合
  /// </summary>
  public StringCollection Receivers
  {
  get{return this.receivers;}
  }
  /// <summary>
  /// 获取或设置邮件主题
  /// </summary>
  public string Subject
  {
  get{return this.subject;}
  set{this.subject=value;}
  }
  /// <summary>
  /// 获取或设置邮件传送者
  /// </summary>
  public string XMailer
  {
  get{return this.xMailer;}
  set{this.xMailer=value;}
  }
  /// <summary>
  /// 获取附件列表
  /// </summary>
  public StringCollection Attachments
  {
  get{return this.attachments;}
  }
  /// <summary>
  /// 获取或设置邮件的编码方式
  /// </summary>
  public MailEncodings MailEncoding
  {
  get{return this.mailEncoding;}
  set{this.mailEncoding=value;}
  }
  /// <summary>
  /// 获取或设置邮件格式
  /// </summary>
  public MailTypes MailType
  {
  get{return this.mailType;}
  set{this.mailType=value;}
  }
  /// <summary>
  /// 获取或设置邮件正文
  /// </summary>
  public byte[] MailBody
  {
  get{return this.mailBody;}
  set{this.mailBody=value;}
  }
}
/// <summary>
/// 邮件编码
/// </summary>
public enum MailEncodings
{
  GB2312,
  ASCII,
  Unicode,
  UTF8
}
/// <summary>
/// 邮件格式
/// </summary>
public enum MailTypes
{
  Html,
  Text
}
/// <summary>
/// smtp服务器的验证方式
/// </summary>
public enum SmtpValidateTypes
{
  /// <summary>
  /// 不需要验证
  /// </summary>
  None,
  /// <summary>
  /// 通用的auth login验证
  /// </summary>
  Login,
  /// <summary>
  /// 通用的auth plain验证
  /// </summary>
  Plain,
  /// <summary>
  /// CRAM-MD5验证
  /// </summary>
  CRAMMD5
}
/// <summary>
/// 邮件发送类
/// </summary>
public class KSN_Smtp
{
  #region "member fields"
  /// <summary>
  /// 连接对象
  /// </summary>
  private TcpClient tc;
  /// <summary>
  /// 网络流
  /// </summary>
  private NetworkStream ns;
  /// <summary>
  /// 错误的代码字典
  /// </summary>
  private StringDictionary errorCodes=new StringDictionary();
  /// <summary>
  /// 操作执行成功后的响应代码字典
  /// </summary>
  private StringDictionary rightCodes=new StringDictionary();
  /// <summary>
  /// 执行过程中错误的消息
  /// </summary>
  private string errorMessage="";
  /// <summary>
  /// 记录操作日志
  /// </summary>
  private string logs="";
  /// <summary>
  /// 主机登陆的验证方式
  /// </summary>
  private StringCollection validateTypes=new StringCollection();
  /// <summary>
  /// 换行常数
  /// </summary>
  private const string CRLF="\r\n";
  private string serverName="smtp";
  private string logPath=null;
  private string userid=null;
  private string password=null;
  private string mailEncodingName="GB2312";
  private bool sendIsComplete=false;
  private SmtpValidateTypes smtpValidateType=SmtpValidateTypes.Login;
  #endregion
  #region "propertys"
  /// <summary>
  /// 获取最后一此程序执行中的错误消息
  /// </summary>
  public string ErrorMessage
  {
  get{return this.errorMessage;}
  }
  /// <summary>
  /// 获取或设置日志输出路径
  /// </summary>
  public string LogPath
  {
  get
  {
    return this.logPath;
  }
  set{this.logPath=value;}
  }
  /// <summary>
  /// 获取或设置登陆smtp服务器的帐号
  /// </summary>
  public string UserID
  {
  get{return this.userid;}
  set{this.userid=value;}
  }
  /// <summary>
  /// 获取或设置登陆smtp服务器的密码
  /// </summary>
  public string Password
  {
  get{return this.password;}
  set{this.password=value;}
  }
  /// <summary>
  /// 获取或设置要使用登陆Smtp服务器的验证方式
  /// </summary>
  public SmtpValidateTypes SmtpValidateType
  {
  get{return this.smtpValidateType;}
  set{this.smtpValidateType=value;}
  }
  #endregion
  #region "construct functions"
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="server">主机名</param>
  /// <param name="port">端口</param>
  public  KSN_Smtp(string server,int port)
  {
  tc=new TcpClient(server,port);
  ns=tc.GetStream();
  this.serverName=server;
  this.initialFields();
  }
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="ip">主机ip</param>
  /// <param name="port">端口</param>
  public KSN_Smtp(IPAddress ip,int port)
  {
  IPEndPoint endPoint=new IPEndPoint(ip,port);
  tc=new TcpClient(endPoint);
  ns=tc.GetStream();
  this.serverName=ip.ToString();
  this.initialFields();
  }
  #endregion
  #region "methods"
  private void initialFields() //初始化连接
  {
  logs="================"+DateTime.Now.ToLongDateString()+"    "+DateTime.Now.ToLongTimeString()+"==============="+CRLF;
  //*****************************************************************
  //错误的状态码
  //*****************************************************************
  errorCodes.Add("421","服务未就绪,关闭传输通道");
  errorCodes.Add("432","需要一个密码转换");
  errorCodes.Add("450","要求的邮件操作未完成,邮箱不可用(如:邮箱忙)");
  errorCodes.Add("451","放弃要求的操作,要求的操作未执行");
  errorCodes.Add("452","系统存储不足,要求的操作未完成");
  errorCodes.Add("454","临时的认证失败");
  errorCodes.Add("500","邮箱地址错误");
  errorCodes.Add("501","参数格式错误");
  errorCodes.Add("502","命令不可实现");
  errorCodes.Add("503","命令的次序不正确");
  errorCodes.Add("504","命令参数不可实现");
  errorCodes.Add("530","需要认证");
  errorCodes.Add("534","认证机制过于简单");
  errorCodes.Add("538","当前请求的认证机制需要加密");
  errorCodes.Add("550","当前的邮件操作未完成,邮箱不可用(如:邮箱未找到或邮箱不能用)");
  errorCodes.Add("551","用户非本地,请尝试<forward-path>");
  errorCodes.Add("552","过量的存储分配,制定的操作未完成");
  errorCodes.Add("553","邮箱名不可用,如:邮箱地址的格式错误");
  errorCodes.Add("554","传送失败");
  errorCodes.Add("535","用户身份验证失败");
  //****************************************************************
  //操作执行成功后的状态码
  //****************************************************************
  rightCodes.Add("220","服务就绪");
  rightCodes.Add("221","服务关闭传输通道");
  rightCodes.Add("235","验证成功");
  rightCodes.Add("250","要求的邮件操作完成");
  rightCodes.Add("251","非本地用户,将转发向<forward-path>");
  rightCodes.Add("334","服务器响应验证Base64字符串");
  rightCodes.Add("354","开始邮件输入,以<CRLF>.<CRLF>结束");
  //读取系统回应
  StreamReader reader=new StreamReader(ns);
  logs+=reader.ReadLine()+CRLF;
  }
  /// <summary>
  /// 向SMTP发送命令
  /// </summary>
  /// <param name="cmd"></param>
  private string sendCommand(string cmd,bool isMailData)
  {
  if(cmd!=null && cmd.Trim()!=string.Empty)
  {
    byte[] cmd_b=null;
    if(!isMailData)//不是邮件数据
    cmd+=CRLF;

    logs+=cmd;
    //开始写入邮件数据
    if(!isMailData)
    {
    cmd_b=Encoding.ASCII.GetBytes(cmd);
    ns.Write(cmd_b,0,cmd_b.Length);
    }
    else
    {
    cmd_b=Encoding.GetEncoding(this.mailEncodingName).GetBytes(cmd);
    ns.BeginWrite(cmd_b,0,cmd_b.Length,new AsyncCallback(this.asyncCallBack),null);
    }
    //读取服务器响应
    StreamReader reader=new StreamReader(ns);
    string response=reader.ReadLine();
    logs+=response+CRLF;
    //检查状态码
    string statusCode=response.Substring(0,3);
    bool isExist=false;
    bool isRightCode=true;
    foreach(string err in this.errorCodes.Keys)
    {
    if(statusCode==err)
    {
      isExist=true;
      isRightCode=false;
      break;
    }
    }
    foreach(string right in this.rightCodes.Keys)
    {
    if(statusCode==right)
    {
      isExist=true;
      break;
    }
    }
    //根据状态码来处理下一步的动作
    if(!isExist) //不是合法的SMTP主机
    {
    this.setError("不是合法的SMTP主机,或服务器拒绝服务");
    }
    else if(!isRightCode)//命令没能成功执行
    {
    this.setError(statusCode+":"+this.errorCodes[statusCode]);
    }
    else //命令成功执行
    {
    this.errorMessage="";
    }
    return response;
  }
  else
  {
    return null;
  }
  }
  /// <summary>
  /// 通过auth login方式登陆smtp服务器
  /// </summary>
  private void landingByLogin()
  {
  string base64UserId=this.convertBase64String(this.UserID,"ASCII");
  string base64Pass=this.convertBase64String(this.Password,"ASCII");
  //握手
  this.sendCommand("helo "+this.serverName,false);
  //开始登陆
  this.sendCommand("auth login",false);
  this.sendCommand(base64UserId,false);
  this.sendCommand(base64Pass,false);
  }
  /// <summary>
  /// 通过auth plain方式登陆服务器
  /// </summary>
  private void landingByPlain()
  {
  string NULL=((char)0).ToString();
  string loginStr=NULL+this.UserID+NULL+this.Password;
  string base64LoginStr=this.convertBase64String(loginStr,"ASCII");
  //握手
  this.sendCommand("helo "+this.serverName,false);
  //登陆
  this.sendCommand(base64LoginStr,false);
  }
  /// <summary>
  /// 通过auth CRAM-MD5方式登陆
  /// </summary>
  private void landingByCRAMMD5()
  {
  //握手
  this.sendCommand("helo "+this.serverName,false);
  //登陆
  string response=this.sendCommand("auth CRAM-MD5",false);
  //得到服务器返回的标识
  string identifier=response.Remove(0,4);
  //用MD5加密标识
  KSN_MACTripleDES mac=new KSN_MACTripleDES();
  mac.Key=this.Password;
  mac.Data=Encoding.ASCII.GetBytes(identifier);
  string hash=mac.GetHashValue();
  //发送用户帐号信息
  this.sendCommand(this.UserID+" "+hash,false);
  }
  /// <summary>
  /// 发送邮件
  /// </summary>
  /// <returns></returns>
  public bool SendMail(MailMessage mail)
  {
  bool isSended=true;
  try
  {
    //检测发送邮件的必要条件
    if(mail.Sender==null)
    {
    this.setError("没有设置发信人");
    }
    if(mail.Receivers.Count==0)
    {
    this.setError("至少要有一个收件人");
    }
    if(this.SmtpValidateType!=SmtpValidateTypes.None)
    {
    if(this.userid==null || this.password==null)
    {
      this.setError("当前设置需要smtp验证,但是没有给出登陆帐号");
    }
    }
    //开始登陆
    switch(this.SmtpValidateType)
    {
    case SmtpValidateTypes.None:
      this.sendCommand("helo "+this.serverName,false);
      break;
    case SmtpValidateTypes.Login:
      this.landingByLogin();
      break;
    case SmtpValidateTypes.Plain:
      this.landingByPlain();
      break;
    case SmtpValidateTypes.CRAMMD5:
      this.landingByCRAMMD5();
      break;
    default:
      break;
    }
    //初始化邮件会话(对应SMTP命令mail)
    this.sendCommand("mail from:<"+mail.Sender+">",false);
    //标识收件人(对应SMTP命令Rcpt)
    foreach(string receive in mail.Receivers)
    {
    this.sendCommand("rcpt to:<"+receive+">",false);
    }
    //标识开始输入邮件内容(Data)
    this.sendCommand("data",false);
    //开始编写邮件内容
    string message="Subject:"+mail.Subject+CRLF;
    message+="X-mailer:"+mail.XMailer+CRLF;
    message+="MIME-Version:1.0"+CRLF;
    if(mail.Attachments.Count==0)//没有附件
    {
    if(mail.MailType==MailTypes.Text) //文本格式
    {
      message+="Content-Type:text/plain;"+CRLF+" ".PadRight(8,' ')+"charset=\""+
      mail.MailEncoding.ToString()+"\""+CRLF;
      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;
      if(mail.MailBody!=null)
      message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF+CRLF+CRLF+"."+CRLF;
    }
    else//Html格式
    {
      message+="Content-Type:multipart/alertnative;"+CRLF+" ".PadRight(8,' ')+"boundary"
      +"=\"=====003_Dragon310083331177_=====\""+CRLF+CRLF+CRLF;
      message+="This is a multi-part message in MIME format"+CRLF+CRLF;
      message+="--=====003_Dragon310083331177_====="+CRLF;
      message+="Content-Type:text/html;"+CRLF+" ".PadRight(8,' ')+"charset=\""+
      mail.MailEncoding.ToString().ToLower()+"\""+CRLF;
      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;
      if(mail.MailBody!=null)
      message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF+CRLF;
      message+="--=====003_Dragon310083331177_=====--"+CRLF+CRLF+CRLF+"."+CRLF;
    }
    }
    else//有附件
    {
    //处理要在邮件中显示的每个附件的数据
    StringCollection attatchmentDatas=new StringCollection();
    foreach(string path in mail.Attachments)
    {
      if(!File.Exists(path))
      {
      this.setError("指定的附件没有找到"+path);
      }
      else
      {
      //得到附件的字节流
      FileInfo file=new FileInfo(path);
      FileStream fs=new FileStream(path,FileMode.Open,FileAccess.Read);
      if(fs.Length>(long)int.MaxValue)
      {
        this.setError("附件的大小超出了最大限制");
      }
      byte[] file_b=new byte[(int)fs.Length];
      fs.Read(file_b,0,file_b.Length);
      fs.Close();
      string attatchmentMailStr="Content-Type:application/octet-stream;"+CRLF+" ".PadRight(8,' ')+"name="+
        "\""+file.Name+"\""+CRLF;
      attatchmentMailStr+="Content-Transfer-Encoding:base64"+CRLF;
      attatchmentMailStr+="Content-Disposition:attachment;"+CRLF+" ".PadRight(8,' ')+"filename="+
        "\""+file.Name+"\""+CRLF+CRLF;
      attatchmentMailStr+=Convert.ToBase64String(file_b,0,file_b.Length)+CRLF+CRLF;
      attatchmentDatas.Add(attatchmentMailStr);
      }
    }
    //设置邮件信息
    if(mail.MailType==MailTypes.Text) //文本格式
    {
      message+="Content-Type:multipart/mixed;"+CRLF+" ".PadRight(8,' ')+"boundary=\"=====001_Dragon320037612222_=====\""
      +CRLF+CRLF;
      message+="This is a multi-part message in MIME format."+CRLF+CRLF;
      message+="--=====001_Dragon320037612222_====="+CRLF;
      message+="Content-Type:text/plain;"+CRLF+" ".PadRight(8,' ')+"charset=\""+mail.MailEncoding.ToString().ToLower()+"\""+CRLF;
      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;
      if(mail.MailBody!=null)
      message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF;
      foreach(string s in attatchmentDatas)
      {
      message+="--=====001_Dragon320037612222_====="+CRLF+s+CRLF+CRLF;
      }
      message+="--=====001_Dragon320037612222_=====--"+CRLF+CRLF+CRLF+"."+CRLF;
    }
    else
    {
      message+="Content-Type:multipart/mixed;"+CRLF+" ".PadRight(8,' ')+"boundary=\"=====001_Dragon255511664284_=====\""
      +CRLF+CRLF;
      message+="This is a multi-part message in MIME format."+CRLF+CRLF;
      message+="--=====001_Dragon255511664284_====="+CRLF;
      message+="Content-Type:text/html;"+CRLF+" ".PadRight(8,' ')+"charset=\""+mail.MailEncoding.ToString().ToLower()+"\""+CRLF;
      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;
      if(mail.MailBody!=null)
      message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF+CRLF;
      for(int i=0;i<attatchmentDatas.Count;i++)
      {
      message+="--=====001_Dragon255511664284_====="+CRLF+attatchmentDatas[i]+CRLF+CRLF;
      }
      message+="--=====001_Dragon255511664284_=====--"+CRLF+CRLF+CRLF+"."+CRLF;
    }
    }
    //发送邮件数据
    this.mailEncodingName=mail.MailEncoding.ToString();
    this.sendCommand(message,true);
    if(this.sendIsComplete)
    this.sendCommand("QUIT",false);
  }
  catch
  {
    isSended=false;
  }
  finally
  {
    this.disconnect();
    //输出日志文件
    if(this.LogPath!=null)
    {
    FileStream fs=null;
    if(File.Exists(this.LogPath))
    {
      fs=new FileStream(this.LogPath,FileMode.Append,FileAccess.Write);
      this.logs=CRLF+CRLF+this.logs;
    }
    else
      fs=new FileStream(this.LogPath,FileMode.Create,FileAccess.Write);
    byte[] logPath_b=Encoding.GetEncoding("gb2312").GetBytes(this.logs);
    fs.Write(logPath_b,0,logPath_b.Length);
    fs.Close();
    }
  }
  return isSended;
  }
  /// <summary>
  /// 异步写入数据
  /// </summary>
  /// <param name="result"></param>
  private void asyncCallBack(IAsyncResult result)
  {
  if(result.IsCompleted)
    this.sendIsComplete=true;
  }
  /// <summary>
  /// 关闭连接
  /// </summary>
  private void disconnect()
  {
  try
  {
    ns.Close();
    tc.Close();
  }
  catch
  {
    ;
  }
  }
  /// <summary>
  /// 设置出现错误时的动作
  /// </summary>
  /// <param name="errorStr"></param>
  private void setError(string errorStr)
  {
  this.errorMessage=errorStr;
  logs+=this.errorMessage+CRLF+"【邮件处理动作中止】"+CRLF;
  this.disconnect();
  throw new ApplicationException("");
  }
  /// <summary>
  ///将字符串转换为base64
  /// </summary>
  /// <param name="str"></param>
  /// <param name="encodingName"></param>
  /// <returns></returns>
  private string convertBase64String(string str,string encodingName)
  {
  byte[] str_b=Encoding.GetEncoding(encodingName).GetBytes(str);
  return Convert.ToBase64String(str_b,0,str_b.Length);
  }
  #endregion
}
}


B13层 发表时间: 06-07-26 00:58

论坛: 黑客进阶

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号