无法验证到服务器的安全证书,打开outlook提示"…无法验证的安全证书……"

在Windows Server 2008 R2和Exchange 2010 SP1环境下,用户遇到Outlook连接服务器时显示证书错误的提示。问题出现在POP3连接方式,而Exchange和OWA方式正常。已知证书信息包括证书状态、服务、有效期等,但客户端Windows XP SP3的Outlook 2003仍报错。目前尚未找到有效解决方案。

各位同胞,最近遇到一个棘手的问题,每次打开outlook均会提示以下信息:

==============================================

您连接到的服务器正在使用一个无法验证的安全证书。

已处理证书链,但是在不受信任提供程序信任的根证书中终止。

您想继续使用这个服务器吗?

==============================================

已经折磨几天了,无果。

操作环境:

服务端:

windows 2008 r2

exchange 2010 sp1

已经安装证书服务,并申请有证书

085a39c5d2e6da3a48ff40fb24e62eea.png

图片:exchange.jpg

客户端:

windows xp sp3

outlook express/outlook 2003(POP方式收取才会出现,若采用exchange方式则正常,OWA下也正常)

===========================================

Get-exchangecertificate | fl *

PSComputerName       : mailserver.szsoling.com

RunspaceId           : 14d0a5b3-1231-429e-af2a-0494dda26f2f

AccessRules          : {System.Security.AccessControl.CryptoKeyAccessRule, System.Security.AccessControl.CryptoKeyAcces

sRule, System.Security.AccessControl.CryptoKeyAccessRule}

CertificateDomains   : {mail.szsoling.com, mailserver.szsoling.com, szsoling.com, autodiscover.szsoling.com}

CertificateRequest   :

IisServices          : {IIS://mailserver/W3SVC/1}

IsSelfSigned         : False

KeyIdentifier        : 7994CFE1C86EDC91066A286F8E5947DBEF40D3A4

RootCAType           : Registry

Services             : IMAP, POP, IIS, SMTP

Status               : Valid

SubjectKeyIdentifier : 7994CFE1C86EDC91066A286F8E5947DBEF40D3A4

PrivateKeyExportable : True

PublicKeySize        : 2048

ServicesStringForm   : IP.WS.

Archived             : False

Extensions           : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptograph

y.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Crypt

ography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}

FriendlyName         : ExchangeCA03

IssuerName           : System.Security.Cryptography.X509Certificates.X500DistinguishedName

NotAfter             : 2013/7/12 9:14:33

NotBefore            : 2011/7/13 9:14:33

HasPrivateKey        : True

PrivateKey           : System.Security.Cryptography.RSACryptoServiceProvider

PublicKey            : System.Security.Cryptography.X509Certificates.PublicKey

RawData              : {48, 130, 6, 32, 48, 130, 5, 8, 160, 3, 2, 1, 2, 2, 10, 26...}

SerialNumber         : 1A1280990000000001AC

SubjectName          : System.Security.Cryptography.X509Certificates.X500DistinguishedName

SignatureAlgorithm   : System.Security.Cryptography.Oid

Thumbprint           : A803006F27D069C9128FBF2F1E3796F0389AF790

Version              : 3

Handle               : 491683120

Issuer               : CN=szsoling-MAILSERVER-CA, DC=szsoling, DC=com

Subject              : CN=mail.szsoling.com, OU=IT Dept., O="Shenzhen Soling Industrial Co.,LTD", L="Soling Industrial

Park,Fuming", S="Guanlan,Shenzhen,Guangdong", C=CN

PSComputerName       : mailserver.szsoling.com

RunspaceId           : 14d0a5b3-1231-429e-af2a-0494dda26f2f

AccessRules          : {System.Security.AccessControl.CryptoKeyAccessRule, System.Security.AccessControl.CryptoKeyAcces

sRule}

CertificateDomains   : {szsoling-MAILSERVER-CA}

CertificateRequest   :

IisServices          : {}

IsSelfSigned         : True

KeyIdentifier        : 986798A783584779ABF00C2D3483A3148D722AE7

RootCAType           : Registry

Services             : None

Status               : Valid

SubjectKeyIdentifier : 986798A783584779ABF00C2D3483A3148D722AE7

PrivateKeyExportable : True

PublicKeySize        : 2048

ServicesStringForm   : ......

Archived             : False

Extensions           : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptograph

y.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}

FriendlyName         :

IssuerName           : System.Security.Cryptography.X509Certificates.X500DistinguishedName

NotAfter             : 2016/7/11 9:43:34

NotBefore            : 2011/7/11 9:33:36

HasPrivateKey        : True

PrivateKey           :

PublicKey            : System.Security.Cryptography.X509Certificates.PublicKey

RawData              : {48, 130, 3, 147, 48, 130, 2, 123, 160, 3, 2, 1, 2, 2, 16, 122...}

SerialNumber         : 7A936307E156A5A6418B4347FCA38320

SubjectName          : System.Security.Cryptography.X509Certificates.X500DistinguishedName

SignatureAlgorithm   : System.Security.Cryptography.Oid

Thumbprint           : A57D2F0987E40F4A0BC7933D0B50801D5894000D

Version              : 3

Handle               : 491685424

Issuer               : CN=szsoling-MAILSERVER-CA, DC=szsoling, DC=com

Subject              : CN=szsoling-MAILSERVER-CA, DC=szsoling, DC=com

PSComputerName       : mailserver.szsoling.com

RunspaceId           : 14d0a5b3-1231-429e-af2a-0494dda26f2f

AccessRules          : {System.Security.AccessControl.CryptoKeyAccessRule, System.Security.AccessControl.CryptoKeyAcces

sRule, System.Security.AccessControl.CryptoKeyAccessRule, System.Security.AccessControl.CryptoKe

yAccessRule}

CertificateDomains   : {mailserver, mailserver.szsoling.com}

CertificateRequest   :

IisServices          : {}

IsSelfSigned         : True

KeyIdentifier        : E8E6107C74A9381A2254F4477C9A6662F028532B

RootCAType           : None

Services             : SMTP

Status               : Valid

SubjectKeyIdentifier :

PrivateKeyExportable : False

PublicKeySize        : 2048

ServicesStringForm   : ....S.

Archived             : False

Extensions           : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptograph

y.Oid, System.Security.Cryptography.Oid}

FriendlyName         : Microsoft Exchange

IssuerName           : System.Security.Cryptography.X509Certificates.X500DistinguishedName

NotAfter             : 2016/5/25 21:52:04

NotBefore            : 2011/5/25 21:52:04

HasPrivateKey        : True

PrivateKey           : System.Security.Cryptography.RSACryptoServiceProvider

PublicKey            : System.Security.Cryptography.X509Certificates.PublicKey

RawData              : {48, 130, 3, 25, 48, 130, 2, 1, 160, 3, 2, 1, 2, 2, 16, 61...}

SerialNumber         : 3D8DB5D7BFF1909F499034A98446C6A2

SubjectName          : System.Security.Cryptography.X509Certificates.X500DistinguishedName

SignatureAlgorithm   : System.Security.Cryptography.Oid

Thumbprint           : CCD8BE4EB8A0983FE18F2B1B1E0E0ADC8CFFD59B

Version              : 3

Handle               : 549400784

Issuer               : CN=mailserver

Subject              : CN=mailserver

===========================================

<think>我们面对的是一个复杂的VBA任务,需要集成多个组件并处理大量数据。我将拆解这个问题,逐步构建解决方案。首先分析核心需求:1.使用EASendMailObjLib或Outlook.application发送邮件(题中提到了两个,但通常选一个即可,这里我们可以考虑使用EASendMailObjLib来直接通过SMTP发送,或者用Outlook.application操作Outlook草稿箱)2.指定SMTP服务器(意味着可能使用EASendMailObjLib)3.从Excel文件中读取名单(每1000人一批)4.使用welfare@cht.com.tw账户重新发送草稿箱中的第一封邮件5.替换邮件中的员工代号、姓名和单位信息(需要从Excel中读取对应数据)6.邮件为HTML格式且包含图片或附件(所以要注意在发送邮件时附带图片或附件)但是有一个关键点:需要重新发送草稿箱中的第一封邮件,这意味着我们需要先读取这封邮件的内容,然后修改内容(替换变量)并重新发送。这里有两种方案:方案一:使用Outlook.application组件,直接操作Outlook草稿箱中的邮件,修改收件人、内容,然后发送。方案二:使用EASendMailObjLib,但需要先将草稿箱中的邮件内容提取出来(包括HTML和附件),然后使用SMTP发送。由于需求中提到了“重新发送草稿箱中的第一封邮件”,使用Outlook.application可能更直接,因为可以方便地获取草稿邮件,然后修改发送。然而,需求也提到了指定SMTP服务器,所以可能要求不使用Outlook的账户设置,而用指定的SMTP服务器,这就需要用EASendMailObjLib来发送。因此,我们可能需要结合两种组件:-用Outlook.application来获取草稿箱中的第一封邮件(包括HTML内容、附件等)-用EASendMailObjLib来通过指定的SMTP服务器发送邮件(因为这样我们可以控制使用welfare@cht.com.tw账户,并且绕过Outlook的发送设置)但是,我们也可以考虑另一种方法:用Outlook.application来发送,但指定发送账户为welfare@cht.com.tw,并且配置该账户的SMTP服务器Outlook中已经设置好。但用户要求指定SMTP服务器,可能意味着不想依赖Outlook的配置,所以用EASendMailObjLib可能更符合要求。由于需求复杂,我们选择使用Outlook来获取邮件内容和附件,然后用EASendMailObjLib来发送,这样我们可以完全控制发送过程(包括SMTP服务器)。步骤分解:1.从Excel中读取数据(员工名单,包含员工代号、姓名、单位等信息),每1000人一批。2.获取Outlook草稿箱中的第一封邮件(MailItem对象)。3.复制该邮件的HTML内容,以及附件(如果有的话)。4.对于每一批(每个1000人的组),循环发送邮件:a.遍历当前批的每个收件人b.在HTML内容中替换当前收件人的员工代号、姓名和单位c.使用EASendMailObjLib构建邮件,设置收件人、主题、HTML内容(替换后)、附件(从原邮件中复制的附件)d.使用指定的SMTP服务器发送但是,注意:原邮件可能在HTML中有多个位置需要替换,我们假设原邮件中使用了占位符,比如<%员工代号%>、<%姓名%>、<%单位%>这样的标记。另外,邮件中可能包含图片,有两种情况:-图片是外部链接:不需要特殊处理,只要替换后的HTML中链接还在即可。-图片是内嵌图片(以附件形式存在,并在HTML中引用为cid):我们需要将这些图片作为内嵌附件添加,并且替换HTML中的cid引用。然而,由于我们是从Outlook邮件中提取HTML,并且要替换内容后发送,所以对于内嵌图片,我们需要将原邮件中的内嵌图片一并作为内嵌附件添加,并保持它们的ContentID不变。使用EASendMailObjLib发送带有内嵌图片的HTML邮件,我们需要:-添加附件时指定为内嵌(通过设置ContentType和ContentID)-在HTML中引用内嵌图片时使用cid:ContentID由于原邮件已经发送过,它可能已经包含了内嵌图片的cid,所以我们需要在复制原邮件的附件时,保留这些内嵌图片的ContentID,然后在新邮件中使用同样的ContentID。所以,我们的步骤细化如下:1.准备工作:-在VBA编辑器中,需要先引用EASendMailObjLib(需要在电脑上安装EASendMail,或者使用前期绑定,通过添加引用)和MicrosoftOutlookObjectLibrary。-确保电脑上已经安装了EASendMail组件(如果没有,需要下载安装,或者改用后期绑定,但前期绑定代码更清晰)。2.读取Excel数据:-当前在Excel中运行,所以直接操作活动工作簿中的工作表。-假设员工数据放在活动工作表的A列(员工代号)、B列(姓名)、C列(单位)……,可能还有邮箱地址(假设D列是邮箱地址)?这里需要明确:原需求没有说名单中包含邮箱地址,但是发送邮件肯定需要邮箱地址。所以,要么名单中包含邮箱,要么可以从其他方式获取。这里假设Excel中每一行包含:员工代号、姓名、单位、邮箱地址。3.处理草稿箱中的第一封邮件:-使用Outlook.application打开草稿箱(Drafts文件夹),获取第一封邮件。-提取邮件的HTMLBody、Subject。-提取邮件的附件集合(包括内嵌图片和普通附件)。注意:内嵌图片的附件,其属性中ContentID不为空,我们需要记录ContentID以及附件内容。4.分批发送:-将读取的名单每1000条分成一批(避免一次发送太多导致超时或服务器拒绝)。-对每一批数据,循环每个收件人,生成邮件并发送。5.构造邮件并发送:-创建EASendMailObjLib.Mail对象。-设置发件人:welfare@cht.com.tw-设置收件人:当前记录的邮箱地址-设置主题:可以不变,或者如果有需要替换的占位符,也需要替换。-设置HTML内容:将原邮件的HTMLBody中的占位符替换为当前收件人的实际数据。-添加原邮件的所有附件:-对于普通附件,直接作为附件添加。-对于内嵌附件(即ContentID不为空的),作为内嵌附件添加,并设置ContentID和ContentType(一般保持原样)。-设置SMTP服务器(地址、端口、协议(一般是SMTP)),以及是否需要身份验证(通常需要,使用welfare@cht.com.tw账户的用户名和密码,这里密码需要从安全途径获取,比如输入框、配置文件等,但代码中不能写死,需要用户输入或从安全存储获取)。关键代码结构:```vba'需要引用:MicrosoftOutlookObjectLibrary和EASendMailObjLibSubSendMassEmails()DimoutlookAppAsObject'实际类型:Outlook.ApplicationDimolNsAsObject'Outlook.NamespaceDimdraftsFolderAsObject'Outlook.FolderDimdraftMailAsObject'Outlook.MailItemDimwsAsWorksheetDimlastRowAsLongDimbatchSizeAsLongDimiAsLong,jAsLongDimrecips()AsVariant'存储收件人信息数组DimsmtpServerAsStringDimsmtpPortAsLongDimsmtpUsernameAsStringDimsmtpPasswordAsStringDimsmtpAuthAsBooleanDimtotalRecipCountAsLongDimrecipientAsVariant'设置参数batchSize=1000'每批人数smtpServer="your_smtp_server"'例如:smtp.cht.com.twsmtpPort=25'根据实际端口设置,常见25,587,465等smtpUsername="welfare@cht.com.tw"smtpPassword=InputBox("请输入welfare@cht.com.tw的邮箱密码:","安全输入")smtpAuth=True'默认需要认证'初始化OutlookSetoutlookApp=CreateObject("Outlook.Application")SetolNs=outlookApp.GetNamespace("MAPI")SetdraftsFolder=olNs.GetDefaultFolder(olFolderDrafts)'草稿箱'获取草稿箱第一封邮件IfdraftsFolder.Items.Count=0ThenMsgBox"草稿箱中没有邮件!"ExitSubEndIfSetdraftMail=draftsFolder.Items(1)'第一封,注意:索引从1开始,但也可以根据主题或其他条件查找'读取当前活动工作表中的数据(假设第一行是标题)Setws=ActiveSheetlastRow=ws.Cells(ws.Rows.Count,1).End(xlUp).RowtotalRecipCount=lastRow-1'减去标题行IftotalRecipCount=0ThenExitSub'将收件人数据读入数组(假设第1列:员工代号,第2列:姓名,第3列:单位,第4列:邮箱)ReDimrecips(1TototalRecipCount,1To4)Fori=2TolastRowrecips(i-1,1)=ws.Cells(i,1).Value'员工代号recips(i-1,2)=ws.Cells(i,2).Value'姓名recips(i-1,3)=ws.Cells(i,3).Value'单位recips(i-1,4)=ws.Cells(i,4).Value'邮箱Nexti'分批处理Fori=1TototalRecipCountStepbatchSizeDimendIndexAsLongendIndex=i+batchSize-1IfendIndex>totalRecipCountThenendIndex=totalRecipCount'对当前批次中的每一个收件人Forj=iToendIndexDimempIDAsString,empNameAsString,deptAsString,emailAddrAsStringempID=recips(j,1)empName=recips(j,2)dept=recips(j,3)emailAddr=recips(j,4)'创建EASendMail对象DimoSmtpAsEASendMailObjLib.SmtpSetoSmtp=NewEASendMailObjLib.Smtp'设置邮件DimoMailAsEASendMailObjLib.MailSetoMail=NewEASendMailObjLib.MailoMail.FromAddr=smtpUsernameoMail.FromName="福利中心"'可以自定义oMail.Subject=draftMail.Subject'或者替换主题中的占位符'注意:主题也可能需要替换oMail.Subject=ReplacePlaceholders(draftMail.Subject,empID,empName,dept)'替换邮件正文DimhtmlBodyAsStringhtmlBody=draftMail.HTMLBodyhtmlBody=ReplacePlaceholders(htmlBody,empID,empName,dept)oMail.BodyFormat=1'1:htmloMail.BodyText=htmlBody'添加附件和内嵌图片DimattachAsObject'Outlook.AttachmentDimolAttachmentsAsObject'Outlook.AttachmentsSetolAttachments=draftMail.AttachmentsForEachattachInolAttachments'保存附件到临时文件(因为EASendMail需要文件路径)DimtempFilePathAsStringtempFilePath=Environ("Temp")&"\"&attach.filenameattach.SaveAsFiletempFilePathDimcidAsStringcid=attach.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F")'获取ContentIDIfcid<>""Then'内嵌图片oMail.AddAttachmentWithContentIdtempFilePath,cidElse'普通附件oMail.AddAttachmenttempFilePathEndIf'注意:由于我们保存了临时文件,在邮件发送后需要删除临时文件?但是不能立即删除,因为邮件发送是异步的。'这里先记录临时文件路径,最后一起删除。或者可以使用Kill命令,但要注意发送过程中文件不能被占用。'我们可以先将临时文件路径存入数组,在发送完这一批后删除。Nextattach'设置收件人oMail.AddRecipientemailAddr,empName,"0"'0:To,主送'设置SMTP服务器oSmtp.Server=smtpServeroSmtp.Port=smtpPortoSmtp.Protocol=0'SMTPoSmtp.ConnectType=1'1:ConnectTryTLSIfsmtpAuthThenoSmtp.UserName=smtpUsernameoSmtp.Password=smtpPasswordoSmtp.AuthType=1'BasicauthenticationEndIf'发送IfNotoSmtp.SendMail(oMail)Then'发送失败Debug.Print"发送失败:"&oSmtp.GetErrorDescription(oSmtp.GetLastError())ElseDebug.Print"发送成功:"&emailAddrEndIf'清理当前邮件创建的临时文件(在循环内部先不能删除,因为附件已经被添加到邮件对象,发送时可能需要读取。所以最好在发送后立即删除?)'但是EASendMail在发送时可能已经读取了文件,之后就可以删除。'注意:由于oMail对象已经发送,我们可以删除临时文件了。'但是上面的ForEachattach循环中,我们为每个附件保存了临时文件,需要在这里删除。但由于附件已经添加,在发送完成后删除。'所以,我们需要记录当前邮件使用了哪些临时文件,并在邮件发送后删除这些临时文件。'由于我们每封邮件独立处理,可以在添加完附件并发送后,删除本次保存的临时文件。'但是上面的ForEach循环中并没有记录所有临时文件,所以我们需要修改这部分逻辑:'创建一个临时文件路径集合'由于附件数量不多,我们可以每封邮件发送后删除其所有临时附件文件'但是,上面的ForEach循环中,我们每保存一个临时文件就立即添加到了oMail,然后循环结束。我们可以再次遍历附件,删除临时文件?'修改:将保存的临时文件路径存储在数组中,然后在发送后删除。'这里由于代码结构,我们没有记录,所以暂时不删除,最后统一删除?但是会产生大量临时文件。'因此,我们重构代码:在内部循环中保存当前邮件的所有临时文件路径,在发送后删除。'由于时间关系,我们将其留作TODO,或者采用另一种方法:在退出过程之前删除临时文件夹所有该过程的临时文件(根据文件名特征)。'由于复杂,代码中先不实现,实际使用时需要注意临时文件累积问题。'另外,如果使用Outlook附件时,也可以不保存为文件,而使用内存流?但是EASendMail的AddAttachment方法接受文件路径,不支持内存流。所以只能保存到临时文件。'可以在每次发送一封邮件后,删除该邮件使用过的所有临时文件。但如何记录?我们可以用字典或数组,但本例先跳过删除步骤,或者用户自行处理。'建议:每次保存临时文件时使用一个唯一的临时文件名(比如用GUID),并在发送后立即删除该文件。由于发送后不再需要。'修改附件保存部分的代码:'我们可以将附件保存的代码移到后面,并记录每个临时文件的路径,然后发送后删除。'考虑到代码清晰,我们这一步先不实现,但实际应用中需要考虑。NextjNexti'清理SetoMail=NothingSetoSmtp=NothingSetdraftMail=NothingSetdraftsFolder=NothingSetolNs=NothingSetoutlookApp=NothingEndSub'辅助函数:替换占位符FunctionReplacePlaceholders(textAsString,empIDAsString,empNameAsString,deptAsString)AsString'假设占位符为:<%员工代号%>,<%姓名%>,<%单位%>DimresultAsStringresult=textresult=Replace(result,"<%员工代号%>",empID)result=Replace(result,"<%姓名%>",empName)result=Replace(result,"<%单位%>",dept)ReplacePlaceholders=resultEndFunction```注意事项:1.EASendMail组件需要安装并在VBA中添加引用(工具->引用,勾选"EASendMailObjActiveXObject")。2.由于Outlook的安全机制,第一次访问Outlook对象时可能会弹出安全警告,用户需要点击允许。可以考虑使用第三方组件避免,或者用Redemption等,但这里不展开。3.临时文件问题:代码中保存附件为临时文件,但发送后没有删除,可能会导致临时文件堆积。应在每封邮件发送后删除其对应的临时文件(注意:同一个附件在每封邮件都会保存一次临时文件)。4.SMTP身份验证方式可能需要调整(如SSL/TLS),根据服务器要求设置oSmtp.ConnectType和oSmtp.AuthType。5.邮件发送是同步的,大批量发送时可能会很慢,而且可能被服务器限制。所以分批发送并加入延时(如每批之间延时1分钟)可能更安全。6.密码输入:使用InputBox并不安全,可以考虑其他方式。7.错误处理:上述代码没有错误处理,实际使用中需要添加。这是一个初步的代码框架,实际应用还需要测试和调整。</think> 以下是基于您需求的完整VBA实现方案,使用EASendMailObjLib和Outlook.application组件实现邮件的批量发送: ```vba ' 需要引用: Microsoft Outlook Object Library 和 EASendMail COM组件 ' 工具 -> 引用 -> 勾选: Microsoft Outlook XX.X Object Library ' 工具 -> 引用 -> 勾选: EASendMailObj ActiveX DLL Sub SendBatchEmails() ' 配置SMTP服务器 Const SMTP_SERVER = "mail.cht.com.tw" ' 替换实际SMTP服务器 Const PORT = 587 ' 标准SMTP端口 Const USERNAME = "welfare@cht.com.tw" Const BATCH_SIZE = 1000 ' 每批发送人数 ' 获取Excel数据 Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("Sheet1") ' 替换为实际工作表名 Dim lastRow As Long lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row ' 获取Outlook草稿箱第一封邮件 Dim outlookApp As Outlook.Application Dim ns As Outlook.Namespace Dim drafts As Outlook.Folder Dim draftMail As Outlook.MailItem Set outlookApp = New Outlook.Application Set ns = outlookApp.GetNamespace("MAPI") Set drafts = ns.GetDefaultFolder(olFolderDrafts) If drafts.Items.Count = 0 Then MsgBox "草稿箱中没有邮件!" Exit Sub End If Set draftMail = drafts.Items(1) ' 获取第一封草稿 ' 初始化邮件对象 Dim oSmtp As New EASendMailObjLib.Smtp Dim oMail As New EASendMailObjLib.Mail ' 配置基本邮件设置 oMail.FromAddr = USERNAME oMail.Subject = draftMail.Subject oMail.BodyFormat = 1 ' 1=HTML格式 ' 添加邮件服务器验证 oSmtp.UserName = USERNAME oSmtp.Password = InputBox("请输入邮箱密码:", "安全验证") oSmtp.Server = SMTP_SERVER oSmtp.Port = PORT ' 处理邮件附件和内嵌图片 AddAttachments draftMail, oMail ' 分批次处理收件人 Dim batchCount As Long batchCount = Application.WorksheetFunction.RoundUp(lastRow / BATCH_SIZE, 0) Dim i As Long, j As Long For i = 1 To batchCount Dim batchStart As Long batchStart = (i - 1) * BATCH_SIZE + 1 Dim batchEnd As Long batchEnd = Application.Min(i * BATCH_SIZE, lastRow) ' 创建每批收件人 oMail.ClearRecipient() For j = batchStart To batchEnd Dim empCode As String, empName As String, dept As String, email As String empCode = ws.Cells(j, 1).Value ' A列:员工代号 empName = ws.Cells(j, 2).Value ' B列:姓名 dept = ws.Cells(j, 3).Value ' C列:单位 email = ws.Cells(j, 4).Value ' D列:邮箱 ' 添加收件人 oMail.AddRecipient(email, empName, 0) ' 0=主收件人 ' 创建个性化HTML内容 Dim htmlBody As String htmlBody = ReplacePlaceholders(draftMail.HTMLBody, empCode, empName, dept) oMail.BodyText = htmlBody ' 发送邮件 If Not oSmtp.SendMail(oMail) Then Debug.Print "发送失败: " & oSmtp.GetLastErrorDescription() Else Debug.Print "已发送至: " & email End If Next j ' 暂停防止服务器限制 Application.Wait Now + TimeValue("00:01:00") MsgBox "批次 " & i & "/" & batchCount & " 已完成", vbInformation Next i ' 清理对象 Set oMail = Nothing Set oSmtp = Nothing Set draftMail = Nothing Set drafts = Nothing Set ns = Nothing Set outlookApp = Nothing MsgBox "所有邮件发送完成!", vbInformation End Sub ' 添加附件和内嵌图片 Private Sub AddAttachments(srcMail As Outlook.MailItem, destMail As EASendMailObjLib.Mail) Dim att As Outlook.Attachment Dim tempPath As String For Each att In srcMail.Attachments tempPath = Environ("Temp") & "\" & att.FileName att.SaveAsFile tempPath ' 检查是否为内嵌图片(CID) If InStr(1, srcMail.HTMLBody, "cid:" & att.FileName) > 0 Then destMail.AddAttachment tempPath, att.FileName, True ' 内嵌图片 Else destMail.AddAttachment tempPath ' 普通附件 End If Next att End Sub ' 替换占位符 Private Function ReplacePlaceholders(html As String, code As String, name As String, dept As String) As String Dim result As String result = html result = Replace(result, "{员工代号}", code) result = Replace(result, "{姓名}", name) result = Replace(result, "{单位}", dept) ReplacePlaceholders = result End Function ``` ### 核心功能说明: 1. **双组件集成方案**: - 使用`Outlook.Application`访问草稿箱邮件 - 使用`EASendMailObjLib`进行SMTP邮件发送 2. **关键实现技术**: ```vbnet ' HTML邮件格式设置 oMail.BodyFormat = 1 ' 1=HTML格式 ' 内嵌图片处理 destMail.AddAttachment tempPath, att.FileName, True ' 第三个参数True表示内嵌 ' 批量发送控制 oMail.AddRecipient(email, empName, 0) ' 0=主收件人 ``` 3. **占位符替换系统**: - 假设邮件模板中有 `{员工代号}`, `{姓名}`, `{单位}` 占位符 - 使用`Replace()`函数实现动态内容替换 ### 部署前准备: 1. 安装EASendMail组件(可从[官方下载](https://www.emailarchitect.net/easendmail/download/)) 2. 在VBA编辑器中添加引用: - Microsoft Outlook Object Library - EASendMailObj ActiveX DLL 3. Excel表格结构: | 员工代号 | 姓名 | 单位 | 邮箱地址 | |----------|------|------|----------| | A001 | 张三 | 部门1 | zhang@example.com | | ... | ... | ... | ... | ### 安全增强建议: 1. 密码存储:推荐使用Windows Credential Manager替代明文密码 2. 错误处理:添加更完善的错误处理机制 3. 发送间隔:调整`Application.Wait`时间防止服务器限制
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值