[{"data":1,"prerenderedAt":1770},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-through-outlook-from-python":3,"surround:\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-through-outlook-from-python":1762},{"id":4,"title":5,"body":6,"dateModified":1734,"datePublished":1734,"description":1735,"extension":1736,"faq":1737,"meta":1746,"navigation":215,"path":1755,"seo":1756,"slug":1758,"stem":1759,"type":1760,"__hash__":1761},"docs\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-through-outlook-from-python\u002Findex.md","Send an Excel Report Through Outlook from Python",{"type":7,"value":8,"toc":1718},"minimark",[9,19,145,150,175,183,187,341,351,355,362,394,405,409,485,492,562,565,569,572,640,650,654,786,793,797,803,1071,1082,1090,1094,1097,1262,1269,1273,1376,1380,1383,1391,1395,1495,1498,1501,1616,1619,1623,1647,1651,1658,1664,1670,1676,1680,1714],[10,11,12,13,18],"p",{},"Sometimes the requirement is not \"send an email\" but \"send it from my account, with my signature,\nlooking like I sent it\" — a weekly report to clients, an approval request, anything where the\nrecipient should reply to a person. On Windows with Outlook installed, that is a handful of lines\nthrough COM. This guide, part of\n",[14,15,17],"a",{"href":16},"\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002F","Emailing Excel Reports with smtplib",",\ncovers composing, attaching and sending — plus the review-before-send pattern that makes it safe.",[20,21,29,30,29,34,29,38,29,45,29,55,29,62,29,70,29,76,29,81,29,86,29,91,29,97,29,102,29,107,29,110,29,112,29,115,29,119,29,123,29,128,29,131,29,133,29,136,29,140],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"0 0 760 264","img",[25,26],"ol-pick-t","ol-pick-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"Which sending route the requirement calls for",[35,36,37],"desc",{"id":26},"A message that must come from a person's own account with their signature suits Outlook automation, a scheduled job suits the Graph API, and a server with credentials suits SMTP.",[39,40],"rect",{"x":41,"y":41,"width":42,"height":43,"fill":44},"0","760","264","#ffffff",[39,46],{"x":47,"y":48,"width":49,"height":50,"rx":51,"fill":52,"stroke":53,"style":54},"230.0","26","300","56","12","#ebebfd","var(--brand,#5b5cf0)","stroke-width:2px",[56,57,61],"text",{"x":58,"y":59,"style":60},"380.0","60","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Who is the message from?",[39,63],{"x":64,"y":65,"width":66,"height":67,"rx":51,"fill":68,"stroke":69,"style":54},"18.0","148","226.7","84","#fdefd8","var(--gold,#b4740a)",[56,71,75],{"x":72,"y":73,"style":74},"131.35","182","font-size:13px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Outlook COM",[56,77,80],{"x":72,"y":78,"style":79},"204","font-size:11.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","their account, their signature",[82,83],"line",{"x1":72,"y1":84,"x2":72,"y2":85,"stroke":53,"style":54},"87","141",[87,88],"polygon",{"points":89,"fill":90},"131.35,141 126.35,132 136.35,132","#5b5cf0",[56,92,96],{"x":93,"y":94,"style":95},"137.35","116","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:start","a person",[39,98],{"x":99,"y":65,"width":66,"height":67,"rx":51,"fill":100,"stroke":101,"style":54},"266.7","#d9f4f1","var(--teal,#0f9488)",[56,103,106],{"x":104,"y":73,"style":105},"380.04999999999995","font-size:13px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Graph API",[56,108,109],{"x":104,"y":78,"style":79},"no password, scheduled",[82,111],{"x1":104,"y1":84,"x2":104,"y2":85,"stroke":53,"style":54},[87,113],{"points":114,"fill":90},"380.04999999999995,141 375.04999999999995,132 385.04999999999995,132",[56,116,118],{"x":117,"y":94,"style":95},"386.04999999999995","a service",[39,120],{"x":121,"y":65,"width":66,"height":67,"rx":51,"fill":122,"stroke":53,"style":54},"515.4","#f0f4ff",[56,124,127],{"x":125,"y":73,"style":126},"628.75","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","SMTP",[56,129,130],{"x":125,"y":78,"style":79},"where basic auth remains",[82,132],{"x1":125,"y1":84,"x2":125,"y2":85,"stroke":53,"style":54},[87,134],{"points":135,"fill":90},"628.75,141 623.75,132 633.75,132",[56,137,139],{"x":138,"y":94,"style":95},"634.75","a server",[56,141,144],{"x":58,"y":142,"style":143},"252","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","the sender decides the route, not the platform",[146,147,149],"h2",{"id":148},"prerequisites","Prerequisites",[151,152,157],"pre",{"className":153,"code":154,"language":155,"meta":156,"style":156},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pywin32\n","bash","",[158,159,160],"code",{"__ignoreMap":156},[161,162,164,168,172],"span",{"class":82,"line":163},1,[161,165,167],{"class":166},"sMTad","pip",[161,169,171],{"class":170},"srMev"," install",[161,173,174],{"class":170}," pywin32\n",[10,176,177,178,182],{},"Windows, Outlook installed with a configured mail profile, and an interactive session. The same COM\nmechanics used here are covered generally in\n",[14,179,181],{"href":180},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002F","Automating Excel with COM and pywin32",".",[146,184,186],{"id":185},"send-a-report-in-nine-lines","Send a report in nine lines",[151,188,192],{"className":189,"code":190,"language":191,"meta":156,"style":156},"language-python shiki shiki-themes github-light github-dark-high-contrast","import win32com.client as win32\n\noutlook = win32.Dispatch(\"Outlook.Application\")\nmail = outlook.CreateItem(0)                     # 0 = olMailItem\nmail.To = \"finance@example.com\"\nmail.CC = \"ops@example.com\"\nmail.Subject = \"Regional revenue — August 2026\"\nmail.HTMLBody = \"\u003Cp>August figures attached. Totals unchanged from the draft.\u003C\u002Fp>\"\nmail.Attachments.Add(r\"C:\\reports\\regional-2026-08.xlsx\")\nmail.Send()\n","python",[158,193,194,210,217,235,256,267,282,293,304,335],{"__ignoreMap":156},[161,195,196,200,204,207],{"class":82,"line":163},[161,197,199],{"class":198},"s-kum","import",[161,201,203],{"class":202},"skGVy"," win32com.client ",[161,205,206],{"class":198},"as",[161,208,209],{"class":202}," win32\n",[161,211,213],{"class":82,"line":212},2,[161,214,216],{"emptyLinePlaceholder":215},true,"\n",[161,218,220,223,226,229,232],{"class":82,"line":219},3,[161,221,222],{"class":202},"outlook ",[161,224,225],{"class":198},"=",[161,227,228],{"class":202}," win32.Dispatch(",[161,230,231],{"class":170},"\"Outlook.Application\"",[161,233,234],{"class":202},")\n",[161,236,238,241,243,246,249,252],{"class":82,"line":237},4,[161,239,240],{"class":202},"mail ",[161,242,225],{"class":198},[161,244,245],{"class":202}," outlook.CreateItem(",[161,247,41],{"class":248},"sP0c6",[161,250,251],{"class":202},")                     ",[161,253,255],{"class":254},"s-wDw","# 0 = olMailItem\n",[161,257,259,262,264],{"class":82,"line":258},5,[161,260,261],{"class":202},"mail.To ",[161,263,225],{"class":198},[161,265,266],{"class":170}," \"finance@example.com\"\n",[161,268,270,273,276,279],{"class":82,"line":269},6,[161,271,272],{"class":202},"mail.",[161,274,275],{"class":248},"CC",[161,277,278],{"class":198}," =",[161,280,281],{"class":170}," \"ops@example.com\"\n",[161,283,285,288,290],{"class":82,"line":284},7,[161,286,287],{"class":202},"mail.Subject ",[161,289,225],{"class":198},[161,291,292],{"class":170}," \"Regional revenue — August 2026\"\n",[161,294,296,299,301],{"class":82,"line":295},8,[161,297,298],{"class":202},"mail.HTMLBody ",[161,300,225],{"class":198},[161,302,303],{"class":170}," \"\u003Cp>August figures attached. Totals unchanged from the draft.\u003C\u002Fp>\"\n",[161,305,307,310,313,316,320,323,325,328,330,333],{"class":82,"line":306},9,[161,308,309],{"class":202},"mail.Attachments.Add(",[161,311,312],{"class":198},"r",[161,314,315],{"class":170},"\"C:",[161,317,319],{"class":318},"s_b0D","\\r",[161,321,322],{"class":170},"eports",[161,324,319],{"class":318},[161,326,327],{"class":170},"egional-2026-08",[161,329,182],{"class":248},[161,331,332],{"class":170},"xlsx\"",[161,334,234],{"class":202},[161,336,338],{"class":82,"line":337},10,[161,339,340],{"class":202},"mail.Send()\n",[10,342,343,346,347,350],{},[158,344,345],{},"CreateItem(0)"," creates a mail item; the other values create appointments, contacts and tasks.\n",[158,348,349],{},"Attachments.Add"," takes an absolute path — a relative one resolves against Outlook's working\ndirectory rather than the script's, which is a surprising and reproducible way to attach nothing.",[146,352,354],{"id":353},"display-instead-of-sending","Display instead of sending",[10,356,357,358,361],{},"The variant worth adopting as a default during development is ",[158,359,360],{},"Display()",", which opens the composed\nmessage in Outlook and leaves the human to press send. It is also the right permanent behaviour for\nanything going to clients.",[151,363,365],{"className":189,"code":364,"language":191,"meta":156,"style":156},"mail.Display(True)      # modal: blocks until the window is closed\nmail.Display(False)     # opens the window and returns immediately\n",[158,366,367,381],{"__ignoreMap":156},[161,368,369,372,375,378],{"class":82,"line":163},[161,370,371],{"class":202},"mail.Display(",[161,373,374],{"class":248},"True",[161,376,377],{"class":202},")      ",[161,379,380],{"class":254},"# modal: blocks until the window is closed\n",[161,382,383,385,388,391],{"class":82,"line":212},[161,384,371],{"class":202},[161,386,387],{"class":248},"False",[161,389,390],{"class":202},")     ",[161,392,393],{"class":254},"# opens the window and returns immediately\n",[10,395,396,397,400,401,404],{},"Building the whole message and then handing it over is a considerably safer pattern than sending\ndirectly, and it costs one word. A configuration flag that switches between ",[158,398,399],{},"Display"," and ",[158,402,403],{},"Send","\nmeans the same script serves the review workflow and the automated one.",[146,406,408],{"id":407},"keeping-the-signature","Keeping the signature",[20,410,29,415,29,418,29,421,29,424,29,429,29,435,29,441,29,445,29,450,29,453,29,456,29,460,29,463,29,467,29,470,29,473,29,478,29,481],{"viewBox":411,"role":23,"ariaLabelledBy":412,"xmlns":27,"style":28},"0 0 760 232",[413,414],"ol-sig-t","ol-sig-d",[31,416,417],{"id":413},"Keeping the signature Outlook inserts",[35,419,420],{"id":414},"Displaying the message first makes Outlook populate the body with the account's signature, which can then be concatenated behind your own content rather than overwritten.",[39,422],{"x":41,"y":41,"width":42,"height":423,"fill":44},"232",[56,425,428],{"x":58,"y":426,"style":427},"32","font-size:13px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","body composition",[39,430],{"x":431,"y":432,"width":433,"height":434,"rx":51,"fill":68,"stroke":69,"style":54},"24.0","74","208.0","96",[56,436,440],{"x":437,"y":438,"style":439},"128.0","114","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Display(False)",[56,442,444],{"x":437,"y":443,"style":79},"136","signature is inserted",[82,446],{"x1":447,"y1":448,"x2":449,"y2":448,"stroke":53,"style":54},"237.0","122.0","269.0",[87,451],{"points":452,"fill":90},"269.0,122.0 260.0,117.0 260.0,127.0",[39,454],{"x":455,"y":432,"width":433,"height":434,"rx":51,"fill":122,"stroke":53,"style":54},"276.0",[56,457,459],{"x":58,"y":438,"style":458},"font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","read HTMLBody",[56,461,462],{"x":58,"y":443,"style":79},"capture the signature",[82,464],{"x1":465,"y1":448,"x2":466,"y2":448,"stroke":53,"style":54},"489.0","521.0",[87,468],{"points":469,"fill":90},"521.0,122.0 512.0,117.0 512.0,127.0",[39,471],{"x":472,"y":432,"width":433,"height":434,"rx":51,"fill":100,"stroke":101,"style":54},"528.0",[56,474,477],{"x":475,"y":438,"style":476},"632.0","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","prepend content",[56,479,480],{"x":475,"y":443,"style":79},"your text, then it",[56,482,484],{"x":58,"y":483,"style":143},"210","assigning HTMLBody outright discards the signature and its images",[10,486,487,488,491],{},"Setting ",[158,489,490],{},"HTMLBody"," replaces everything, signature included. The trick is to display the message\nfirst — which populates the signature — and then insert content ahead of it.",[151,493,495],{"className":189,"code":494,"language":191,"meta":156,"style":156},"mail = outlook.CreateItem(0)\nmail.To = \"finance@example.com\"\nmail.Subject = \"Regional revenue — August 2026\"\nmail.Display(False)                       # Outlook inserts the signature into HTMLBody\nsignature = mail.HTMLBody\nmail.HTMLBody = \"\u003Cp>August figures attached.\u003C\u002Fp>\" + signature\n",[158,496,497,509,517,525,537,547],{"__ignoreMap":156},[161,498,499,501,503,505,507],{"class":82,"line":163},[161,500,240],{"class":202},[161,502,225],{"class":198},[161,504,245],{"class":202},[161,506,41],{"class":248},[161,508,234],{"class":202},[161,510,511,513,515],{"class":82,"line":212},[161,512,261],{"class":202},[161,514,225],{"class":198},[161,516,266],{"class":170},[161,518,519,521,523],{"class":82,"line":219},[161,520,287],{"class":202},[161,522,225],{"class":198},[161,524,292],{"class":170},[161,526,527,529,531,534],{"class":82,"line":237},[161,528,371],{"class":202},[161,530,387],{"class":248},[161,532,533],{"class":202},")                       ",[161,535,536],{"class":254},"# Outlook inserts the signature into HTMLBody\n",[161,538,539,542,544],{"class":82,"line":258},[161,540,541],{"class":202},"signature ",[161,543,225],{"class":198},[161,545,546],{"class":202}," mail.HTMLBody\n",[161,548,549,551,553,556,559],{"class":82,"line":269},[161,550,298],{"class":202},[161,552,225],{"class":198},[161,554,555],{"class":170}," \"\u003Cp>August figures attached.\u003C\u002Fp>\"",[161,557,558],{"class":198}," +",[161,560,561],{"class":202}," signature\n",[10,563,564],{},"Concatenating rather than replacing preserves the signature's own HTML structure, which matters\nbecause Outlook signatures frequently contain images referenced as embedded content that a naive\nrebuild would break.",[146,566,568],{"id":567},"sending-as-a-shared-mailbox","Sending as a shared mailbox",[10,570,571],{},"Reports often come from a departmental address rather than a person's. Two properties handle it, and\nthey mean different things.",[151,573,575],{"className":189,"code":574,"language":191,"meta":156,"style":156},"mail.SentOnBehalfOfName = \"reports@example.com\"     # needs Send On Behalf rights\n# or, to send as an account configured in this profile:\nfor account in outlook.Session.Accounts:\n    if account.SmtpAddress.lower() == \"reports@example.com\":\n        mail.SendUsingAccount = account\n        break\n",[158,576,577,590,595,609,625,635],{"__ignoreMap":156},[161,578,579,582,584,587],{"class":82,"line":163},[161,580,581],{"class":202},"mail.SentOnBehalfOfName ",[161,583,225],{"class":198},[161,585,586],{"class":170}," \"reports@example.com\"",[161,588,589],{"class":254},"     # needs Send On Behalf rights\n",[161,591,592],{"class":82,"line":212},[161,593,594],{"class":254},"# or, to send as an account configured in this profile:\n",[161,596,597,600,603,606],{"class":82,"line":219},[161,598,599],{"class":198},"for",[161,601,602],{"class":202}," account ",[161,604,605],{"class":198},"in",[161,607,608],{"class":202}," outlook.Session.Accounts:\n",[161,610,611,614,617,620,622],{"class":82,"line":237},[161,612,613],{"class":198},"    if",[161,615,616],{"class":202}," account.SmtpAddress.lower() ",[161,618,619],{"class":198},"==",[161,621,586],{"class":170},[161,623,624],{"class":202},":\n",[161,626,627,630,632],{"class":82,"line":258},[161,628,629],{"class":202},"        mail.SendUsingAccount ",[161,631,225],{"class":198},[161,633,634],{"class":202}," account\n",[161,636,637],{"class":82,"line":269},[161,638,639],{"class":198},"        break\n",[10,641,642,645,646,649],{},[158,643,644],{},"SentOnBehalfOfName"," produces \"Ana on behalf of Reports\" in most clients unless full Send As rights\nare granted. ",[158,647,648],{},"SendUsingAccount"," requires the mailbox to be a configured account in the profile and\nsends as it directly. Which one is available is an Exchange configuration question, not a Python one.",[146,651,653],{"id":652},"attaching-several-files-and-embedding-an-image","Attaching several files and embedding an image",[151,655,657],{"className":189,"code":656,"language":191,"meta":156,"style":156},"import pathlib\n\nfor path in sorted(pathlib.Path(r\"C:\\reports\\august\").glob(\"*.xlsx\")):\n    mail.Attachments.Add(str(path.resolve()))\n\nchart = mail.Attachments.Add(r\"C:\\reports\\revenue.png\")\nchart.PropertyAccessor.SetProperty(\n    \"http:\u002F\u002Fschemas.microsoft.com\u002Fmapi\u002Fproptag\u002F0x3712001F\", \"revenuechart\"\n)\nmail.HTMLBody = '\u003Cp>August figures attached.\u003C\u002Fp>\u003Cimg src=\"cid:revenuechart\">' + signature\n",[158,658,659,666,670,708,719,723,753,758,769,773],{"__ignoreMap":156},[161,660,661,663],{"class":82,"line":163},[161,662,199],{"class":198},[161,664,665],{"class":202}," pathlib\n",[161,667,668],{"class":82,"line":212},[161,669,216],{"emptyLinePlaceholder":215},[161,671,672,674,677,679,682,685,687,689,691,693,696,699,702,705],{"class":82,"line":219},[161,673,599],{"class":198},[161,675,676],{"class":202}," path ",[161,678,605],{"class":198},[161,680,681],{"class":248}," sorted",[161,683,684],{"class":202},"(pathlib.Path(",[161,686,312],{"class":198},[161,688,315],{"class":170},[161,690,319],{"class":318},[161,692,322],{"class":170},[161,694,695],{"class":318},"\\a",[161,697,698],{"class":170},"ugust\"",[161,700,701],{"class":202},").glob(",[161,703,704],{"class":170},"\"*.xlsx\"",[161,706,707],{"class":202},")):\n",[161,709,710,713,716],{"class":82,"line":237},[161,711,712],{"class":202},"    mail.Attachments.Add(",[161,714,715],{"class":248},"str",[161,717,718],{"class":202},"(path.resolve()))\n",[161,720,721],{"class":82,"line":258},[161,722,216],{"emptyLinePlaceholder":215},[161,724,725,728,730,733,735,737,739,741,743,746,748,751],{"class":82,"line":269},[161,726,727],{"class":202},"chart ",[161,729,225],{"class":198},[161,731,732],{"class":202}," mail.Attachments.Add(",[161,734,312],{"class":198},[161,736,315],{"class":170},[161,738,319],{"class":318},[161,740,322],{"class":170},[161,742,319],{"class":318},[161,744,745],{"class":170},"evenue",[161,747,182],{"class":248},[161,749,750],{"class":170},"png\"",[161,752,234],{"class":202},[161,754,755],{"class":82,"line":284},[161,756,757],{"class":202},"chart.PropertyAccessor.SetProperty(\n",[161,759,760,763,766],{"class":82,"line":295},[161,761,762],{"class":170},"    \"http:\u002F\u002Fschemas.microsoft.com\u002Fmapi\u002Fproptag\u002F0x3712001F\"",[161,764,765],{"class":202},", ",[161,767,768],{"class":170},"\"revenuechart\"\n",[161,770,771],{"class":82,"line":306},[161,772,234],{"class":202},[161,774,775,777,779,782,784],{"class":82,"line":337},[161,776,298],{"class":202},[161,778,225],{"class":198},[161,780,781],{"class":170}," '\u003Cp>August figures attached.\u003C\u002Fp>\u003Cimg src=\"cid:revenuechart\">'",[161,783,558],{"class":198},[161,785,561],{"class":202},[10,787,788,789,792],{},"The property tag sets the attachment's content id, which is what lets an ",[158,790,791],{},"\u003Cimg src=\"cid:...\">"," in the\nbody resolve to it. That is the same mechanism SMTP uses for inline images, expressed through MAPI —\nand it is the only reliable way to put a chart in the body rather than beside it, since remote images\nare blocked by default in most clients.",[146,794,796],{"id":795},"driving-outlook-and-excel-together","Driving Outlook and Excel together",[10,798,799,800,182],{},"A common shape for a desktop reporting script is to refresh a workbook, export a range as an image,\nand email the result — three applications, one COM session each. They coexist without difficulty\nprovided each is quit in its own ",[158,801,802],{},"finally",[151,804,806],{"className":189,"code":805,"language":191,"meta":156,"style":156},"import win32com.client as win32\n\ndef refresh_and_send(workbook_path: str, to: str) -> None:\n    excel = win32.DispatchEx(\"Excel.Application\")\n    excel.Visible = False\n    excel.DisplayAlerts = False\n    try:\n        book = excel.Workbooks.Open(workbook_path)\n        try:\n            book.RefreshAll()\n            excel.CalculateUntilAsyncQueriesDone()\n            book.Save()\n            book.Sheets(\"Summary\").ChartObjects(1).Chart.Export(r\"C:\\reports\\chart.png\")\n        finally:\n            book.Close(SaveChanges=False)\n    finally:\n        excel.Quit()\n\n    outlook = win32.Dispatch(\"Outlook.Application\")\n    mail = outlook.CreateItem(0)\n    mail.To = to\n    mail.Subject = \"Refreshed report\"\n    mail.Attachments.Add(workbook_path)\n    mail.Display(False)\n",[158,807,808,818,822,849,864,874,883,890,900,907,912,918,924,962,970,986,994,1000,1005,1019,1033,1044,1055,1061],{"__ignoreMap":156},[161,809,810,812,814,816],{"class":82,"line":163},[161,811,199],{"class":198},[161,813,203],{"class":202},[161,815,206],{"class":198},[161,817,209],{"class":202},[161,819,820],{"class":82,"line":212},[161,821,216],{"emptyLinePlaceholder":215},[161,823,824,827,831,834,836,839,841,844,847],{"class":82,"line":219},[161,825,826],{"class":198},"def",[161,828,830],{"class":829},"s_Opv"," refresh_and_send",[161,832,833],{"class":202},"(workbook_path: ",[161,835,715],{"class":248},[161,837,838],{"class":202},", to: ",[161,840,715],{"class":248},[161,842,843],{"class":202},") -> ",[161,845,846],{"class":248},"None",[161,848,624],{"class":202},[161,850,851,854,856,859,862],{"class":82,"line":237},[161,852,853],{"class":202},"    excel ",[161,855,225],{"class":198},[161,857,858],{"class":202}," win32.DispatchEx(",[161,860,861],{"class":170},"\"Excel.Application\"",[161,863,234],{"class":202},[161,865,866,869,871],{"class":82,"line":258},[161,867,868],{"class":202},"    excel.Visible ",[161,870,225],{"class":198},[161,872,873],{"class":248}," False\n",[161,875,876,879,881],{"class":82,"line":269},[161,877,878],{"class":202},"    excel.DisplayAlerts ",[161,880,225],{"class":198},[161,882,873],{"class":248},[161,884,885,888],{"class":82,"line":284},[161,886,887],{"class":198},"    try",[161,889,624],{"class":202},[161,891,892,895,897],{"class":82,"line":295},[161,893,894],{"class":202},"        book ",[161,896,225],{"class":198},[161,898,899],{"class":202}," excel.Workbooks.Open(workbook_path)\n",[161,901,902,905],{"class":82,"line":306},[161,903,904],{"class":198},"        try",[161,906,624],{"class":202},[161,908,909],{"class":82,"line":337},[161,910,911],{"class":202},"            book.RefreshAll()\n",[161,913,915],{"class":82,"line":914},11,[161,916,917],{"class":202},"            excel.CalculateUntilAsyncQueriesDone()\n",[161,919,921],{"class":82,"line":920},12,[161,922,923],{"class":202},"            book.Save()\n",[161,925,927,930,933,936,939,942,944,946,948,950,953,956,958,960],{"class":82,"line":926},13,[161,928,929],{"class":202},"            book.Sheets(",[161,931,932],{"class":170},"\"Summary\"",[161,934,935],{"class":202},").ChartObjects(",[161,937,938],{"class":248},"1",[161,940,941],{"class":202},").Chart.Export(",[161,943,312],{"class":198},[161,945,315],{"class":170},[161,947,319],{"class":318},[161,949,322],{"class":170},[161,951,952],{"class":318},"\\c",[161,954,955],{"class":170},"hart",[161,957,182],{"class":248},[161,959,750],{"class":170},[161,961,234],{"class":202},[161,963,965,968],{"class":82,"line":964},14,[161,966,967],{"class":198},"        finally",[161,969,624],{"class":202},[161,971,973,976,980,982,984],{"class":82,"line":972},15,[161,974,975],{"class":202},"            book.Close(",[161,977,979],{"class":978},"sa561","SaveChanges",[161,981,225],{"class":198},[161,983,387],{"class":248},[161,985,234],{"class":202},[161,987,989,992],{"class":82,"line":988},16,[161,990,991],{"class":198},"    finally",[161,993,624],{"class":202},[161,995,997],{"class":82,"line":996},17,[161,998,999],{"class":202},"        excel.Quit()\n",[161,1001,1003],{"class":82,"line":1002},18,[161,1004,216],{"emptyLinePlaceholder":215},[161,1006,1008,1011,1013,1015,1017],{"class":82,"line":1007},19,[161,1009,1010],{"class":202},"    outlook ",[161,1012,225],{"class":198},[161,1014,228],{"class":202},[161,1016,231],{"class":170},[161,1018,234],{"class":202},[161,1020,1022,1025,1027,1029,1031],{"class":82,"line":1021},20,[161,1023,1024],{"class":202},"    mail ",[161,1026,225],{"class":198},[161,1028,245],{"class":202},[161,1030,41],{"class":248},[161,1032,234],{"class":202},[161,1034,1036,1039,1041],{"class":82,"line":1035},21,[161,1037,1038],{"class":202},"    mail.To ",[161,1040,225],{"class":198},[161,1042,1043],{"class":202}," to\n",[161,1045,1047,1050,1052],{"class":82,"line":1046},22,[161,1048,1049],{"class":202},"    mail.Subject ",[161,1051,225],{"class":198},[161,1053,1054],{"class":170}," \"Refreshed report\"\n",[161,1056,1058],{"class":82,"line":1057},23,[161,1059,1060],{"class":202},"    mail.Attachments.Add(workbook_path)\n",[161,1062,1064,1067,1069],{"class":82,"line":1063},24,[161,1065,1066],{"class":202},"    mail.Display(",[161,1068,387],{"class":248},[161,1070,234],{"class":202},[10,1072,1073,1074,1077,1078,1081],{},"Note the asymmetry: Excel is started with ",[158,1075,1076],{},"DispatchEx"," so quitting it cannot disturb a workbook the\nuser has open, while Outlook uses ",[158,1079,1080],{},"Dispatch"," deliberately — the point is to use the person's own\nrunning Outlook and their profile. Quitting Outlook is not appropriate at all, and the script simply\nleaves it as it found it.",[10,1083,1084,1085,1089],{},"The lifecycle rules for the Excel half are the ones in\n",[14,1086,1088],{"href":1087},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fclose-excel-cleanly-and-avoid-orphan-com-processes\u002F","Close Excel Cleanly and Avoid Orphan COM Processes",";\nOutlook does not accumulate orphans the same way because it is a single-instance application.",[146,1091,1093],{"id":1092},"building-the-recipient-list-from-the-data","Building the recipient list from the data",[10,1095,1096],{},"Where the report is per-region or per-client, the recipients belong beside the data rather than in\nthe script. Reading them from a sheet in the same workbook keeps the distribution list editable by\nthe people who own it.",[151,1098,1100],{"className":189,"code":1099,"language":191,"meta":156,"style":156},"import pandas as pd\n\nrecipients = pd.read_excel(\"report.xlsx\", sheet_name=\"Distribution\")\nfor row in recipients.itertuples(index=False):\n    mail = outlook.CreateItem(0)\n    mail.To = row.Email\n    mail.Subject = f\"{row.Region} revenue — August 2026\"\n    mail.HTMLBody = f\"\u003Cp>Hello {row.Name}, your regional figures are attached.\u003C\u002Fp>\"\n    mail.Attachments.Add(rf\"C:\\reports\\august\\{row.Region}.xlsx\")\n    mail.Display(False)\n",[158,1101,1102,1114,1118,1143,1165,1177,1186,1211,1233,1254],{"__ignoreMap":156},[161,1103,1104,1106,1109,1111],{"class":82,"line":163},[161,1105,199],{"class":198},[161,1107,1108],{"class":202}," pandas ",[161,1110,206],{"class":198},[161,1112,1113],{"class":202}," pd\n",[161,1115,1116],{"class":82,"line":212},[161,1117,216],{"emptyLinePlaceholder":215},[161,1119,1120,1123,1125,1128,1131,1133,1136,1138,1141],{"class":82,"line":219},[161,1121,1122],{"class":202},"recipients ",[161,1124,225],{"class":198},[161,1126,1127],{"class":202}," pd.read_excel(",[161,1129,1130],{"class":170},"\"report.xlsx\"",[161,1132,765],{"class":202},[161,1134,1135],{"class":978},"sheet_name",[161,1137,225],{"class":198},[161,1139,1140],{"class":170},"\"Distribution\"",[161,1142,234],{"class":202},[161,1144,1145,1147,1150,1152,1155,1158,1160,1162],{"class":82,"line":237},[161,1146,599],{"class":198},[161,1148,1149],{"class":202}," row ",[161,1151,605],{"class":198},[161,1153,1154],{"class":202}," recipients.itertuples(",[161,1156,1157],{"class":978},"index",[161,1159,225],{"class":198},[161,1161,387],{"class":248},[161,1163,1164],{"class":202},"):\n",[161,1166,1167,1169,1171,1173,1175],{"class":82,"line":258},[161,1168,1024],{"class":202},[161,1170,225],{"class":198},[161,1172,245],{"class":202},[161,1174,41],{"class":248},[161,1176,234],{"class":202},[161,1178,1179,1181,1183],{"class":82,"line":269},[161,1180,1038],{"class":202},[161,1182,225],{"class":198},[161,1184,1185],{"class":202}," row.Email\n",[161,1187,1188,1190,1192,1195,1198,1202,1205,1208],{"class":82,"line":284},[161,1189,1049],{"class":202},[161,1191,225],{"class":198},[161,1193,1194],{"class":198}," f",[161,1196,1197],{"class":170},"\"",[161,1199,1201],{"class":1200},"sSjpA","{",[161,1203,1204],{"class":202},"row.Region",[161,1206,1207],{"class":1200},"}",[161,1209,1210],{"class":170}," revenue — August 2026\"\n",[161,1212,1213,1216,1218,1220,1223,1225,1228,1230],{"class":82,"line":295},[161,1214,1215],{"class":202},"    mail.HTMLBody ",[161,1217,225],{"class":198},[161,1219,1194],{"class":198},[161,1221,1222],{"class":170},"\"\u003Cp>Hello ",[161,1224,1201],{"class":1200},[161,1226,1227],{"class":202},"row.Name",[161,1229,1207],{"class":1200},[161,1231,1232],{"class":170},", your regional figures are attached.\u003C\u002Fp>\"\n",[161,1234,1235,1237,1240,1243,1245,1247,1249,1252],{"class":82,"line":306},[161,1236,712],{"class":202},[161,1238,1239],{"class":198},"rf",[161,1241,1242],{"class":170},"\"C:\\reports\\august\\",[161,1244,1201],{"class":1200},[161,1246,1204],{"class":202},[161,1248,1207],{"class":1200},[161,1250,1251],{"class":170},".xlsx\"",[161,1253,234],{"class":202},[161,1255,1256,1258,1260],{"class":82,"line":337},[161,1257,1066],{"class":202},[161,1259,387],{"class":248},[161,1261,234],{"class":202},[10,1263,1264,1265,182],{},"Displaying rather than sending is doubly worth it here: a mistake in the distribution sheet becomes\ntwelve draft windows a person can close, rather than twelve messages already gone. The per-region\nfile generation that feeds it is covered in\n",[14,1266,1268],{"href":1267},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Fgenerate-one-excel-report-per-region-in-a-loop\u002F","Generate One Excel Report per Region in a Loop",[146,1270,1272],{"id":1271},"common-pitfalls","Common pitfalls",[1274,1275,1276,1292],"table",{},[1277,1278,1279],"thead",{},[1280,1281,1282,1286,1289],"tr",{},[1283,1284,1285],"th",{},"Symptom",[1283,1287,1288],{},"Cause",[1283,1290,1291],{},"Fix",[1293,1294,1295,1307,1322,1333,1348,1365],"tbody",{},[1280,1296,1297,1301,1304],{},[1298,1299,1300],"td",{},"Nothing is attached",[1298,1302,1303],{},"A relative path resolved against Outlook's directory",[1298,1305,1306],{},"Pass an absolute path",[1280,1308,1309,1312,1317],{},[1298,1310,1311],{},"The signature disappears",[1298,1313,1314,1316],{},[158,1315,490],{}," was assigned rather than appended",[1298,1318,1319,1321],{},[158,1320,440],{}," first, then concatenate",[1280,1323,1324,1327,1330],{},[1298,1325,1326],{},"A security prompt appears on send",[1298,1328,1329],{},"Outlook's programmatic-access guard",[1298,1331,1332],{},"Run under a trusted setup; there is no code-side override",[1280,1334,1335,1340,1343],{},[1298,1336,1337,1339],{},[158,1338,644],{}," is ignored",[1298,1341,1342],{},"The account lacks Send On Behalf rights",[1298,1344,1345,1346],{},"Grant the right in Exchange, or use ",[158,1347,648],{},[1280,1349,1350,1353,1359],{},[1298,1351,1352],{},"The script hangs",[1298,1354,1355,1358],{},[158,1356,1357],{},"Display(True)"," is modal and waits for the window",[1298,1360,1361,1362,1364],{},"Use ",[158,1363,440],{}," in unattended contexts",[1280,1366,1367,1370,1373],{},[1298,1368,1369],{},"Works interactively, fails scheduled",[1298,1371,1372],{},"No desktop session or profile",[1298,1374,1375],{},"Use Graph or SMTP for scheduled sends",[146,1377,1379],{"id":1378},"when-not-to-use-this","When not to use this",[10,1381,1382],{},"Outlook automation is the right tool for a script a person runs from their own machine and the wrong\none for anything on a schedule. It needs an interactive session, a configured profile and a licensed\ninstallation; it triggers security prompts under conditions that are hard to predict; and it fails in\nways that are invisible to a scheduler because the failure is a dialog.",[10,1384,1385,1386,1390],{},"For a nightly report, use SMTP or the Graph API — the latter covered in\n",[14,1387,1389],{"href":1388},"\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-with-microsoft-graph-api\u002F","Send an Excel Report with the Microsoft Graph API",".\nKeep Outlook for the case it is genuinely best at: a person pressing a button and reviewing what goes\nout under their own name.",[146,1392,1394],{"id":1393},"performance-and-scale","Performance and scale",[20,1396,29,1401,29,1404,29,1407,29,1410,29,1417,29,1422,29,1428,29,1433,29,1437,29,1441,29,1446,29,1451,29,1455,29,1458,29,1461,29,1464,29,1471,29,1476,29,1481,29,1484,29,1488,29,1491],{"viewBox":1397,"role":23,"ariaLabelledBy":1398,"xmlns":27,"style":28},"0 0 760 201",[1399,1400],"ol-batch-t","ol-batch-d",[31,1402,1403],{"id":1399},"Handing messages to the outbox is not delivery",[35,1405,1406],{"id":1400},"Outlook accepts the messages and returns immediately, so a script finishes before anything is sent and a server rejection surfaces after the run has ended.",[39,1408],{"x":41,"y":41,"width":42,"height":1409,"fill":44},"201",[39,1411],{"x":1412,"y":1413,"width":1414,"height":1415,"rx":1416,"fill":68,"stroke":69,"style":54},"20","28","270.0","139","14",[56,1418,1421],{"x":1419,"y":1420,"style":74},"155.0","54","what the script sees",[82,1423],{"x1":1424,"y1":1425,"x2":1426,"y2":1425,"stroke":69,"style":1427},"36","64","274.0","stroke-width:1px",[56,1429,1432],{"x":1419,"y":1430,"style":1431},"86","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","50 items created",[56,1434,1436],{"x":1419,"y":1435,"style":1431},"109","returns in seconds",[56,1438,1440],{"x":1419,"y":1439,"style":1431},"132","no errors",[39,1442],{"x":1443,"y":1413,"width":1414,"height":1415,"rx":1416,"fill":1444,"stroke":1445,"style":54},"470.0","#fee8f2","var(--accent,#d81b73)",[56,1447,1450],{"x":1448,"y":1420,"style":1449},"605.0","font-size:13px;font-weight:700;fill:var(--accent,#d81b73);text-anchor:middle","what actually happened",[82,1452],{"x1":1453,"y1":1425,"x2":1454,"y2":1425,"stroke":1445,"style":1427},"486.0","724.0",[56,1456,1457],{"x":1448,"y":1430,"style":1431},"queued in the outbox",[56,1459,1460],{"x":1448,"y":1435,"style":1431},"sending continues after",[56,1462,1463],{"x":1448,"y":1439,"style":1431},"rejections arrive later",[39,1465],{"x":1466,"y":1467,"width":1468,"height":1469,"rx":1470,"fill":52,"stroke":53},"316.0","78.5","128","38","19",[56,1472,1475],{"x":58,"y":1473,"style":1474},"102.5","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","poll the outbox",[82,1477],{"x1":1478,"y1":1479,"x2":1480,"y2":1479,"stroke":53,"style":54},"295.0","97.5","309.0",[87,1482],{"points":1483,"fill":90},"309.0,97.5 300.0,92.5 300.0,102.5",[82,1485],{"x1":1486,"y1":1479,"x2":1487,"y2":1479,"stroke":53,"style":54},"449.0","463.0",[87,1489],{"points":1490,"fill":90},"463.0,97.5 454.0,92.5 454.0,102.5",[56,1492,1494],{"x":58,"y":1493,"style":143},"187","wait for the queue to drain before reporting success",[10,1496,1497],{},"Outlook sends through the profile's outbox, which means a script that creates fifty messages hands\nthem all to Outlook and returns before any of them have left. That is fast from the script's point of\nview and slow from the recipient's, and it makes error handling awkward — a message rejected by the\nserver fails after your script has finished.",[10,1499,1500],{},"For batches, the workable pattern is to create the messages, then poll the outbox until it drains:",[151,1502,1504],{"className":189,"code":1503,"language":191,"meta":156,"style":156},"import time\n\noutbox = outlook.Session.GetDefaultFolder(4)      # 4 = olFolderOutbox\ndeadline = time.monotonic() + 300\nwhile outbox.Items.Count and time.monotonic() \u003C deadline:\n    time.sleep(2)\nif outbox.Items.Count:\n    raise TimeoutError(f\"{outbox.Items.Count} message(s) still queued\")\n",[158,1505,1506,1513,1517,1535,1551,1570,1580,1588],{"__ignoreMap":156},[161,1507,1508,1510],{"class":82,"line":163},[161,1509,199],{"class":198},[161,1511,1512],{"class":202}," time\n",[161,1514,1515],{"class":82,"line":212},[161,1516,216],{"emptyLinePlaceholder":215},[161,1518,1519,1522,1524,1527,1530,1532],{"class":82,"line":219},[161,1520,1521],{"class":202},"outbox ",[161,1523,225],{"class":198},[161,1525,1526],{"class":202}," outlook.Session.GetDefaultFolder(",[161,1528,1529],{"class":248},"4",[161,1531,377],{"class":202},[161,1533,1534],{"class":254},"# 4 = olFolderOutbox\n",[161,1536,1537,1540,1542,1545,1548],{"class":82,"line":237},[161,1538,1539],{"class":202},"deadline ",[161,1541,225],{"class":198},[161,1543,1544],{"class":202}," time.monotonic() ",[161,1546,1547],{"class":198},"+",[161,1549,1550],{"class":248}," 300\n",[161,1552,1553,1556,1559,1562,1564,1567],{"class":82,"line":258},[161,1554,1555],{"class":198},"while",[161,1557,1558],{"class":202}," outbox.Items.Count ",[161,1560,1561],{"class":198},"and",[161,1563,1544],{"class":202},[161,1565,1566],{"class":198},"\u003C",[161,1568,1569],{"class":202}," deadline:\n",[161,1571,1572,1575,1578],{"class":82,"line":269},[161,1573,1574],{"class":202},"    time.sleep(",[161,1576,1577],{"class":248},"2",[161,1579,234],{"class":202},[161,1581,1582,1585],{"class":82,"line":284},[161,1583,1584],{"class":198},"if",[161,1586,1587],{"class":202}," outbox.Items.Count:\n",[161,1589,1590,1593,1596,1599,1602,1604,1606,1609,1611,1614],{"class":82,"line":295},[161,1591,1592],{"class":198},"    raise",[161,1594,1595],{"class":248}," TimeoutError",[161,1597,1598],{"class":202},"(",[161,1600,1601],{"class":198},"f",[161,1603,1197],{"class":170},[161,1605,1201],{"class":1200},[161,1607,1608],{"class":202},"outbox.Items.Count",[161,1610,1207],{"class":1200},[161,1612,1613],{"class":170}," message(s) still queued\"",[161,1615,234],{"class":202},[10,1617,1618],{},"Beyond a few dozen messages, the throttling and delivery-tracking limitations make a real mail API\nthe better choice regardless of platform.",[146,1620,1622],{"id":1621},"conclusion","Conclusion",[10,1624,1625,1627,1628,765,1631,400,1634,1636,1637,1640,1641,1643,1644,1646],{},[158,1626,345],{},", set ",[158,1629,1630],{},"To",[158,1632,1633],{},"Subject",[158,1635,490],{},", add attachments by absolute path, and either\n",[158,1638,1639],{},"Send()"," or ",[158,1642,360],{}," — the latter being the safer default for anything a person should see before\nit goes. Preserve the signature by displaying first and concatenating, use ",[158,1645,648],{}," for a\nshared mailbox, and keep the whole approach for interactive machines: scheduled sending belongs to\nSMTP or Graph.",[146,1648,1650],{"id":1649},"frequently-asked-questions","Frequently asked questions",[10,1652,1653,1657],{},[1654,1655,1656],"strong",{},"Does this need Outlook running?","\nNot running, but installed and configured with a profile. Dispatching Outlook.Application starts it if it is closed, and the message is sent from whichever account the profile has as its default unless you set SendUsingAccount.",[10,1659,1660,1663],{},[1654,1661,1662],{},"Can I send from a shared mailbox?","\nYes — set SentOnBehalfOfName to the shared mailbox address, provided the signed-in account has Send As or Send On Behalf rights. Without those rights the send fails after the message is composed, which is a confusing place to find out.",[10,1665,1666,1669],{},[1654,1667,1668],{},"Will this work on a server?","\nNo, in the sense that matters: Outlook automation needs an interactive desktop session with a configured profile, and Microsoft does not support it from a service. For scheduled sending use the Graph API or SMTP.",[10,1671,1672,1675],{},[1654,1673,1674],{},"How do I include the user's signature?","\nCall Display() on the message first, which populates the signature into HTMLBody, then insert your content ahead of the existing HTML rather than replacing it. Setting HTMLBody outright discards the signature.",[146,1677,1679],{"id":1678},"related","Related",[1681,1682,1683,1690,1695,1702,1707],"ul",{},[1684,1685,1686,1687,1689],"li",{},"Up one level: ",[14,1688,17],{"href":16}," — the cross-platform route and message construction.",[1684,1691,1692,1694],{},[14,1693,1389],{"href":1388}," — the scheduled-job alternative with no desktop dependency.",[1684,1696,1697,1701],{},[14,1698,1700],{"href":1699},"\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fattach-multiple-excel-files-to-one-email-in-python\u002F","Attach Multiple Excel Files to One Email in Python"," — batching attachments and keeping the message under limits.",[1684,1703,1704,1706],{},[14,1705,181],{"href":180}," — the COM mechanics this uses.",[1684,1708,1709,1713],{},[14,1710,1712],{"href":1711},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fhandle-com-errors-and-excel-dialog-prompts-in-python\u002F","Handle COM Errors and Excel Dialog Prompts in Python"," — the prompts that stall an unattended send.",[1715,1716,1717],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_b0D, html code.shiki .s_b0D{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":156,"searchDepth":212,"depth":212,"links":1719},[1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733],{"id":148,"depth":212,"text":149},{"id":185,"depth":212,"text":186},{"id":353,"depth":212,"text":354},{"id":407,"depth":212,"text":408},{"id":567,"depth":212,"text":568},{"id":652,"depth":212,"text":653},{"id":795,"depth":212,"text":796},{"id":1092,"depth":212,"text":1093},{"id":1271,"depth":212,"text":1272},{"id":1378,"depth":212,"text":1379},{"id":1393,"depth":212,"text":1394},{"id":1621,"depth":212,"text":1622},{"id":1649,"depth":212,"text":1650},{"id":1678,"depth":212,"text":1679},"2026-09-04","Compose and send from a real Outlook profile with win32com: attachments by absolute path, the signature preserved, shared-mailbox senders, and Display for review before sending.","md",[1738,1740,1742,1744],{"q":1656,"a":1739},"Not running, but installed and configured with a profile. Dispatching Outlook.Application starts it if it is closed, and the message is sent from whichever account the profile has as its default unless you set SendUsingAccount.",{"q":1662,"a":1741},"Yes — set SentOnBehalfOfName to the shared mailbox address, provided the signed-in account has Send As or Send On Behalf rights. Without those rights the send fails after the message is composed, which is a confusing place to find out.",{"q":1668,"a":1743},"No, in the sense that matters: Outlook automation needs an interactive desktop session with a configured profile, and Microsoft does not support it from a service. For scheduled sending use the Graph API or SMTP.",{"q":1674,"a":1745},"Call Display() on the message first, which populates the signature into HTMLBody, then insert your content ahead of the existing HTML rather than replacing it. Setting HTMLBody outright discards the signature.",{"breadcrumb":1747},[1748,1751,1754],{"name":1749,"item":1750},"Home","\u002F",{"name":1752,"item":1753},"Automating Reporting Workflows","\u002Fautomating-reporting-workflows\u002F",{"name":17,"item":16},"\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-through-outlook-from-python",{"title":5,"description":1757},"Automate Outlook from Python to send Excel reports — CreateItem, attachments, keeping the signature, SentOnBehalfOfName, inline images by content id, and when not to use it.","send-an-excel-report-through-outlook-from-python","automating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-through-outlook-from-python\u002Findex","how-to","Q1YLI3_enijhpsH1WECSpyKhLZ2UPxoefPMPSPI_acs",[1763,1767],{"title":1764,"path":1765,"stem":1766,"children":-1},"Email an Excel Report with an HTML Summary Body","\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Femail-an-excel-report-with-an-html-summary-body","automating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Femail-an-excel-report-with-an-html-summary-body\u002Findex",{"title":1389,"path":1768,"stem":1769,"children":-1},"\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-with-microsoft-graph-api","automating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Fsend-an-excel-report-with-microsoft-graph-api\u002Findex",1788710160076]