Quản lý email outlook qua VBA cần giúp đỡ (6 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Tôi tuân thủ nội quy khi đăng bài

dohungmo

Thành viên mới
Tham gia
4/4/13
Bài viết
39
Được thích
1
Nhờ anh/chị hỗ trợ viết giúp em một file VBA có thể tích hợp với Outlook để hỗ trợ quản lý email hàng ngày một cách thuận tiện hơn. Cụ thể, em cần file này thực hiện được các chức năng sau:
  1. Hiển thị địa chỉ email của người gửi.
  2. Hiển thị tiêu đề email (Subject).
  3. Hiển thị đường link dẫn trực tiếp đến email trong Outlook.
  4. Hiển thị tên tệp đính kèm (nếu có).
  5. Hiển thị ngày và giờ nhận email.
  6. Có nút “Refresh” để cập nhật danh sách email mới.
  7. Cập nhật email theo kiểu tích lũy:
    • Ví dụ: nếu bắt đầu sử dụng file từ ngày 01/05/2024, thì file chỉ cập nhật các email nhận sau ngày này, và không lấy các email trước thời điểm đó.
    • Mỗi lần nhấn “Refresh”, danh sách email mới sẽ được bổ sung thêm vào file, không làm mất các email đã được lưu trước đó.
Em cảm ơn.
 

File đính kèm

Lần chỉnh sửa cuối:
Nhờ anh/chị hỗ trợ viết giúp em một file VBA có thể tích hợp với Outlook để hỗ trợ quản lý email hàng ngày một cách thuận tiện hơn. Cụ thể, em cần file này thực hiện được các chức năng sau:
  1. Hiển thị địa chỉ email của người gửi.
  2. Hiển thị tiêu đề email (Subject).
  3. Hiển thị đường link dẫn trực tiếp đến email trong Outlook.
  4. Hiển thị tên tệp đính kèm (nếu có).
  5. Hiển thị ngày và giờ nhận email.
  6. Có nút “Refresh” để cập nhật danh sách email mới.
  7. Cập nhật email theo kiểu tích lũy:
    • Ví dụ: nếu bắt đầu sử dụng file từ ngày 01/05/2024, thì file chỉ cập nhật các email nhận sau ngày này, và không lấy các email trước thời điểm đó.
    • Mỗi lần nhấn “Refresh”, danh sách email mới sẽ được bổ sung thêm vào file, không làm mất các email đã được lưu trước đó.
Em cảm ơn.
Gửi bạn dùng thử xem sao, cũng lâu lắm rồi không động tay vào code Outlook VBA, hoang mang từ thời điểm Microsoft quyết định đẩy The New Outlook làm ứng dụng chính, dần dần sẽ thay thế ứng dụng Outlook cũ (hay còn gọi là The Classic Outlook), mấy năm trước còn hăng hái dịch hẳn một cuốn sách về chủ đề này dày gần 1000 trang.

1746166933961.png

Module1:
Mã:
Option Explicit

Public Sub ListMails()
    Dim objSh As Excel.Worksheet
    On Error Resume Next
    Set objSh = Sheet1
    If Err.Number <> 0 Then
        Call MsgBox("The required worksheet 'Sheet1' was not found.", vbExclamation, "Error: Worksheet Not Found")
        Exit Sub
    End If
    On Error GoTo 0
    Dim objOlApp As Outlook.Application
    On Error Resume Next
    Set objOlApp = GetObject(, "Outlook.Application")
    If Err.Number = 429 Then
        Call MsgBox("This macro requires a running instance of Outlook. Please try again later!", vbExclamation, "Error: Outlook Not Running")
        Exit Sub
    End If
    On Error GoTo 0
    Dim objFld As Outlook.Folder
    Set objFld = objOlApp.Session.PickFolder
    If objFld Is Nothing Then
        Call MsgBox("Please select a folder to continue", vbExclamation, "Error: Folder Not Specified")
        Exit Sub
    End If
    objSh.Range("C1").Value2 = objFld.FolderPath
    Dim dteDate As Date
    dteDate = CDate(objSh.Range("C2").Value2)
    Dim colItems As Collection
    Set colItems = GetMailsByDate(objOlApp, objFld, dteDate)
    If colItems.Count = 0 Then
        Call MsgBox("No mail item was found that matched the criteria 'after " & CStr(dteDate) & "'", vbInformation, "Search Result")
        Exit Sub
    End If
    Dim lngLastRow As Long, lngRowsCount As Long
    lngRowsCount = objSh.Rows.Count
    lngLastRow = objSh.Cells(lngRowsCount, 1).End(xlUp).Row
    If lngLastRow > 5 Then objSh.Range("A5:G" & CStr(lngLastRow)).ClearContents
    Dim arrResult As Variant, i As Long, j As Long, objResult As MailInfo, strAttFileNames As String
    ReDim arrResult(1 To colItems.Count, 1 To 7) As Variant
    For i = 1 To colItems.Count
        arrResult(i, 1) = i
        Set objResult = colItems.Item(i)
        arrResult(i, 2) = objResult.SenderEmailAddress
        arrResult(i, 3) = objResult.Subject
        If objResult.HasAttachments Then
            For j = 1 To objResult.Attachments.Count
                If j = objResult.Attachments.Count Then
                    strAttFileNames = strAttFileNames & objResult.Attachments.Item(j)
                Else: strAttFileNames = strAttFileNames & objResult.Attachments.Item(j) & ", "
                End If
            Next
            arrResult(i, 4) = strAttFileNames
        End If
        arrResult(i, 5) = objResult.EntryId
        arrResult(i, 6) = objResult.ReceivedTime
    Next
    objSh.Range("A5").Resize(UBound(arrResult), UBound(arrResult, 2)).Value2 = arrResult
    lngLastRow = objSh.Cells(lngRowsCount, 1).End(xlUp).Row
    Dim objCell As Excel.Range, objLinkRange As Excel.Range
    Set objLinkRange = objSh.Range("E5:E" & CStr(lngLastRow))
    For Each objCell In objLinkRange
        objSh.Hyperlinks.Add objCell, "", objCell.Value2, "Open Mail", "Click here to open mail from Outlook"
    Next
End Sub

Public Function GetMailsByDate(ByVal OlApp As Outlook.Application, ByVal Fld As Outlook.Folder, ByVal DateVal As Date) As Collection
    If OlApp Is Nothing Or Fld Is Nothing Then Exit Function
    Dim objMail As Outlook.MailItem
    Dim dteDate As Date, objPA As Outlook.PropertyAccessor
    Set objMail = OlApp.CreateItem(olMailItem)
    Set objPA = objMail.PropertyAccessor
    dteDate = objPA.LocalTimeToUTC(DateVal)
    objMail.Close olDiscard
    Dim strFilter As String
    strFilter = "@SQL=" & Quote("urn:schemas:httpmail:datereceived") & " >= " & SingleQuote(dteDate)
    Const PR_SENDER_EMAIL_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x0C1F001F"
    Const PR_SUBJECT As String = "http://schemas.microsoft.com/mapi/proptag/0x0037001F"
    Const PR_HASATTACH As String = "http://schemas.microsoft.com/mapi/proptag/0x0E1B000B"
    Dim objTbl As Outlook.Table, colResults As Collection, objResult As MailInfo, objRow As Outlook.Row, colAttachmentNames As Collection, objAtt As Outlook.Attachment
    Set colResults = New Collection
    Set objTbl = Fld.GetTable(strFilter)
    With objTbl
        .Columns.RemoveAll
        .Columns.Add "EntryId"
        .Columns.Add PR_SENDER_EMAIL_ADDRESS
        .Columns.Add PR_SUBJECT
        .Columns.Add PR_HASATTACH
        .Columns.Add "urn:schemas:httpmail:datereceived"
        Do Until .EndOfTable
            Set objResult = New MailInfo
            Set objRow = .GetNextRow
            With objResult
                .HasAttachments = objRow(4)
                .Subject = objRow(3)
                .SenderEmailAddress = objRow(2)
                .ReceivedTime = objRow.UTCToLocalTime(5)
                If .HasAttachments Then
                    Set colAttachmentNames = New Collection
                    Set objMail = OlApp.Session.GetItemFromID(objRow(1))
                    For Each objAtt In objMail.Attachments
                        colAttachmentNames.Add objAtt.Filename
                    Next
                    objMail.Close olDiscard
                    Set .Attachments = colAttachmentNames
                End If
                .EntryId = objRow(1)
            End With
            colResults.Add objResult
        Loop
    End With
    Set GetMailsByDate = colResults
End Function

Private Function Quote(ByVal Text As String) As String
    Quote = Chr(34) & Text & Chr(34)
End Function

Private Function SingleQuote(ByVal Text As String) As String
    SingleQuote = Chr(39) & Text & Chr(39)
End Function

MailInfo.cls:

Mã:
Option Explicit

Private m_SenderEmailAddress As String
Private m_Subject As String
Private m_EntryId As String
Private m_HasAttachments As Boolean
Private m_Attachments As New Collection
Private m_ReceivedTime As Date

Public Property Get SenderEmailAddress() As String
    SenderEmailAddress = m_SenderEmailAddress
End Property

Public Property Let SenderEmailAddress(Value As String)
    m_SenderEmailAddress = Value
End Property

Public Property Get Subject() As String
    Subject = m_Subject
End Property

Public Property Let Subject(Value As String)
    m_Subject = Value
End Property

Public Property Get EntryId() As String
    EntryId = m_EntryId
End Property

Public Property Let EntryId(Value As String)
    m_EntryId = Value
End Property

Public Property Get HasAttachments() As Boolean
    HasAttachments = m_HasAttachments
End Property

Public Property Let HasAttachments(Value As Boolean)
    m_HasAttachments = Value
End Property

Public Property Get Attachments() As Collection
    Set Attachments = m_Attachments
End Property

Public Property Set Attachments(Value As Collection)
    Set m_Attachments = Value
End Property

Public Property Get ReceivedTime() As Date
    ReceivedTime = m_ReceivedTime
End Property

Public Property Let ReceivedTime(Value As Date)
    m_ReceivedTime = Value
End Property
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Gửi bạn dùng thử xem sao, cũng lâu lắm rồi không động tay vào code Outlook VBA, hoang mang từ thời điểm Microsoft quyết định đẩy The New Outlook làm ứng dụng chính, dần dần sẽ thay thế ứng dụng Outlook cũ (hay còn gọi là The Classic Outlook), mấy năm trước còn hăng hái dịch hẳn một cuốn sách về chủ đề này dày gần 1000 trang.

View attachment 308041

Module1:
Mã:
Option Explicit

Public Sub ListMails()
    Dim objSh As Excel.Worksheet
    On Error Resume Next
    Set objSh = Sheet1
    If Err.Number <> 0 Then
        Call MsgBox("The required worksheet 'Sheet1' was not found.", vbExclamation, "Error: Worksheet Not Found")
        Exit Sub
    End If
    On Error GoTo 0
    Dim objOlApp As Outlook.Application
    On Error Resume Next
    Set objOlApp = GetObject(, "Outlook.Application")
    If Err.Number = 429 Then
        Call MsgBox("This macro requires a running instance of Outlook. Please try again later!", vbExclamation, "Error: Outlook Not Running")
        Exit Sub
    End If
    On Error GoTo 0
    Dim objFld As Outlook.Folder
    Set objFld = objOlApp.Session.PickFolder
    If objFld Is Nothing Then
        Call MsgBox("Please select a folder to continue", vbExclamation, "Error: Folder Not Specified")
        Exit Sub
    End If
    objSh.Range("C1").Value2 = objFld.FolderPath
    Dim dteDate As Date
    dteDate = CDate(objSh.Range("C2").Value2)
    Dim colItems As Collection
    Set colItems = GetMailsByDate(objOlApp, objFld, dteDate)
    If colItems.Count = 0 Then
        Call MsgBox("No mail item was found that matched the criteria 'after " & CStr(dteDate) & "'", vbInformation, "Search Result")
        Exit Sub
    End If
    Dim lngLastRow As Long, lngRowsCount As Long
    lngRowsCount = objSh.Rows.Count
    lngLastRow = objSh.Cells(lngRowsCount, 1).End(xlUp).Row
    If lngLastRow > 5 Then objSh.Range("A5:G" & CStr(lngLastRow)).ClearContents
    Dim arrResult As Variant, i As Long, j As Long, objResult As MailInfo, strAttFileNames As String
    ReDim arrResult(1 To colItems.Count, 1 To 7) As Variant
    For i = 1 To colItems.Count
        arrResult(i, 1) = i
        Set objResult = colItems.Item(i)
        arrResult(i, 2) = objResult.SenderEmailAddress
        arrResult(i, 3) = objResult.Subject
        If objResult.HasAttachments Then
            For j = 1 To objResult.Attachments.Count
                If j = objResult.Attachments.Count Then
                    strAttFileNames = strAttFileNames & objResult.Attachments.Item(j)
                Else: strAttFileNames = strAttFileNames & objResult.Attachments.Item(j) & ", "
                End If
            Next
            arrResult(i, 4) = strAttFileNames
        End If
        arrResult(i, 5) = objResult.EntryId
        arrResult(i, 6) = objResult.ReceivedTime
    Next
    objSh.Range("A5").Resize(UBound(arrResult), UBound(arrResult, 2)).Value2 = arrResult
    lngLastRow = objSh.Cells(lngRowsCount, 1).End(xlUp).Row
    Dim objCell As Excel.Range, objLinkRange As Excel.Range
    Set objLinkRange = objSh.Range("E5:E" & CStr(lngLastRow))
    For Each objCell In objLinkRange
        objSh.Hyperlinks.Add objCell, "", objCell.Value2, "Open Mail", "Click here to open mail from Outlook"
    Next
End Sub

Public Function GetMailsByDate(ByVal OlApp As Outlook.Application, ByVal Fld As Outlook.Folder, ByVal DateVal As Date) As Collection
    If OlApp Is Nothing Or Fld Is Nothing Then Exit Function
    Dim objMail As Outlook.MailItem
    Dim dteDate As Date, objPA As Outlook.PropertyAccessor
    Set objMail = OlApp.CreateItem(olMailItem)
    Set objPA = objMail.PropertyAccessor
    dteDate = objPA.LocalTimeToUTC(DateVal)
    objMail.Close olDiscard
    Dim strFilter As String
    strFilter = "@SQL=" & Quote("urn:schemas:httpmail:datereceived") & " >= " & SingleQuote(dteDate)
    Const PR_SENDER_EMAIL_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x0C1F001F"
    Const PR_SUBJECT As String = "http://schemas.microsoft.com/mapi/proptag/0x0037001F"
    Const PR_HASATTACH As String = "http://schemas.microsoft.com/mapi/proptag/0x0E1B000B"
    Dim objTbl As Outlook.Table, colResults As Collection, objResult As MailInfo, objRow As Outlook.Row, colAttachmentNames As Collection, objAtt As Outlook.Attachment
    Set colResults = New Collection
    Set objTbl = Fld.GetTable(strFilter)
    With objTbl
        .Columns.RemoveAll
        .Columns.Add "EntryId"
        .Columns.Add PR_SENDER_EMAIL_ADDRESS
        .Columns.Add PR_SUBJECT
        .Columns.Add PR_HASATTACH
        .Columns.Add "urn:schemas:httpmail:datereceived"
        Do Until .EndOfTable
            Set objResult = New MailInfo
            Set objRow = .GetNextRow
            With objResult
                .HasAttachments = objRow(4)
                .Subject = objRow(3)
                .SenderEmailAddress = objRow(2)
                .ReceivedTime = objRow.UTCToLocalTime(5)
                Set colAttachmentNames = New Collection
                Set objMail = OlApp.Session.GetItemFromID(objRow(1))
                For Each objAtt In objMail.Attachments
                    colAttachmentNames.Add objAtt.Filename
                Next
                .EntryId = objRow(1)
                Set .Attachments = colAttachmentNames
                objMail.Close olDiscard
            End With
            colResults.Add objResult
        Loop
    End With
    Set GetMailsByDate = colResults
End Function

Private Function Quote(ByVal Text As String) As String
    Quote = Chr(34) & Text & Chr(34)
End Function

Private Function SingleQuote(ByVal Text As String) As String
    SingleQuote = Chr(39) & Text & Chr(39)
End Function

MailInfo.cls:

Mã:
Option Explicit

Private m_SenderEmailAddress As String
Private m_Subject As String
Private m_EntryId As String
Private m_HasAttachments As Boolean
Private m_Attachments As New Collection
Private m_ReceivedTime As Date

Public Property Get SenderEmailAddress() As String
    SenderEmailAddress = m_SenderEmailAddress
End Property

Public Property Let SenderEmailAddress(Value As String)
    m_SenderEmailAddress = Value
End Property

Public Property Get Subject() As String
    Subject = m_Subject
End Property

Public Property Let Subject(Value As String)
    m_Subject = Value
End Property

Public Property Get EntryId() As String
    EntryId = m_EntryId
End Property

Public Property Let EntryId(Value As String)
    m_EntryId = Value
End Property

Public Property Get HasAttachments() As Boolean
    HasAttachments = m_HasAttachments
End Property

Public Property Let HasAttachments(Value As Boolean)
    m_HasAttachments = Value
End Property

Public Property Get Attachments() As Collection
    Set Attachments = m_Attachments
End Property

Public Property Set Attachments(Value As Collection)
    Set m_Attachments = Value
End Property

Public Property Get ReceivedTime() As Date
    ReceivedTime = m_ReceivedTime
End Property

Public Property Let ReceivedTime(Value As Date)
    m_ReceivedTime = Value
End Property
cảm ơn bác nhiều lắm ạ . Bác ơi , file này chuẩn luôn theo yêu cầu nhưng nó không quét hết tất cả mail đến trong ngày ạ .
 
Lần chỉnh sửa cuối:
Upvote 0
cảm ơn bác nhiều lắm ạ . Bác ơi , file này chuẩn luôn theo yêu cầu nhưng nó không quét hết tất cả mail đến trong ngày ạ .
Bạn kiểm tra lại kết quả xem sao nhé.
Lưu ý chỗ này, máy tính của mình đang để định dạng là MM/dd/yyyy, còn kết quả hiển thị trong bảng tính là dd/MM/yyyy.

1746177542354.png

Chuỗi lọc cũng chỉ có một điều kiện, @SQL="urn:schemas:httpmail:datereceived" >= 'ngày, giờ', tức là lọc ra những thư đã nhận được sau 'ngày, giờ'.
 
Upvote 0
Bạn kiểm tra lại kết quả xem sao nhé.
Lưu ý chỗ này, máy tính của mình đang để định dạng là MM/dd/yyyy, còn kết quả hiển thị trong bảng tính là dd/MM/yyyy.

View attachment 308043

Chuỗi lọc cũng chỉ có một điều kiện, @SQL="urn:schemas:httpmail:datereceived" >= 'ngày, giờ', tức là lọc ra những thư đã nhận được sau 'ngày, giờ'.
1746177886788.png
em đã định dạng theo lời bác mà nó chỉ record được bằng này cái mail trên tổng số 30 cái mail ạ
 
Upvote 0
Upvote 0
Em đã thử rồi ạ , mà nó chỉ hiện ra 1 số email thôi . Vẫn bị sót nhiều lắm bác ạ . Bác view lại file được không ạ
 
Upvote 0
Em đã thử rồi ạ , mà nó chỉ hiện ra 1 số email thôi . Vẫn bị sót nhiều lắm bác ạ . Bác view lại file được không ạ
Bạn có đang dùng Exchange không? Nếu có thì thử kiểm tra cài đặt Offline Settings, bật chế độ Cached Exchange Mode để Outlook tải xuống tất cả các thư từ máy chủ Exchange. Có lẽ VBA chỉ có thể quét được những thư đã được tải về máy tính.

1746180258367.png
 
Upvote 0
Cập nhật code bài viết #2: Bổ sung điều kiện, chỉ lấy thông tin về tập tin đính kèm từ những thư có chứa tập tin đính kèm (PR_HASATTACH = 1), giúp tăng tốc độ xử lý kết quả.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom