msgraph-sdk-dotnet icon indicating copy to clipboard operation
msgraph-sdk-dotnet copied to clipboard

Username/password credentials no longer works for public app

Open MAlabaster opened this issue 1 year ago • 2 comments

Trying to migrate from SDK v4.35 to 5.8. We have a multi-tenant app with consent granted in other tenancies. Authentication code is ` var scopes = new[] { "User.Read", "Mail.ReadWrite", "Mail.ReadWrite.Shared", "Mail.Send", "Mail.Send.Shared" };

            var theOptions = new TokenCredentialOptions
            {
                AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
            };

            var userNamePasswordCredential = new UsernamePasswordCredential(theAccount, thePassword, theTenantID, theAppID,theOptions);
           
            graphClient = new GraphServiceClient(userNamePasswordCredential, scopes);`

This no longer works in v5, when trying to access mailfolders giving this error which suggests it does not work multi-tenant

UsernamePasswordCredential authentication failed: AADSTS50020: User account '{EmailHidden}' from identity provider 'https://sts.windows.net/34dc47b4-7068-4e4c-9fd0-df28979f3c6b/' does not exist in tenant 'Arcivate Ltd' and cannot access the application 'a40a20d3-f53a-4c23-8c98-8cee091b51af'(ARCMailImpMSG) in that tenant.

Expected behavior Token provided

Desktop (please complete the following information):

  • OS: Windows 10 (testing) and 2012 server (productio env.)
  • Browser N/A
  • Version Additional context Add any other context about the problem here.

MAlabaster avatar May 02 '23 11:05 MAlabaster

Thanks for raising this @MAlabaster

Any chance you could share the code sample used to make the call to access the mailfolders in this scenario and confirm that you still used the UsernamePasswordCredential in the previous version of the SDK?

As the error seems to occur during the time of acquiring the token and not on making the call to microsoft graph, are you able to confirm the user exists in the tenant with theTenantID value?

andrueastman avatar May 04 '23 10:05 andrueastman

Hi,

I can confirm that we are currently using our multi-tenant app in production to open email inboxes in different tenancies, read their emails and download attachments using MSG 4.35.0 and Graph.Core 5.9.0 Customers’ mail folders (not necessarily the actual INBOX) in 4 different tenancies are accessed that way, until recently when 2 new customers rejected granting consent to a multi-tenant app so they created their own app and we use Client Credential authorisation.

I’ve attached the source code for the form of a WinForms troubleshooting utility I use to connect to the customers’ mailboxes, filter and download emails. I came across this problem when I added the Client Credential Auth to this app and then upgraded to the v5 library. I can connect to our own accounts using uname/pwd but not accounts in any other tenancy.

If you need any more, just ask.

Martin

Background. We have a system that downloads pdf & tif email attachments which and processes them through OCR extraction and an invoice processing workflow. Previously we were using EWS libraries but with the move to MSGraph we had to come up with an authorisation model that allowed us to easily connect to the 365 mailboxes of customers in different tenancies who didn’t necessarily have Azure proficiency to create an app and then restrict mailbox access to an app with admin consent.

The solution chosen was to use uname/pwd as this required only consent for the account in question to be granted by the customer. That has proved more difficult because usually organisation settings require admin privileges to grant consent.

From: Eastman @.> Sent: Thursday, May 4, 2023 11:23 AM To: microsoftgraph/msgraph-sdk-dotnet @.> Cc: Martin Alabaster @.>; Mention @.> Subject: Re: [microsoftgraph/msgraph-sdk-dotnet] Username/password credentials no longer works for public app (Issue #1868)

Thanks for raising this @MAlabasterhttps://github.com/MAlabaster

Any chance you could share the code sample used to make the call to access the mailfolders in this scenario and confirm that you still used the UsernamePasswordCredential in the previous version of the SDK?

As the error seems to occur during the time of acquiring the token and not on making the call to microsoft graph, are you able to confirm the user exists in the tenant with theTenantID value?

— Reply to this email directly, view it on GitHubhttps://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/1868#issuecomment-1534495584, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AM3IE2S3VEJJMKGMBQXMDODXEN7RZANCNFSM6AAAAAAXS4HKDU. You are receiving this because you were mentioned.Message ID: @.@.>>

Arcivate Ltd is registered in England & Wales, Company No.: 07340236 Registered Office is at Second Floor, Windsor House, 40/41 Great Castle Street, London W1W 8LU. This e-mail is intended solely for the person or entity to which it is addressed and may contain confidential and/or privileged information. Any review, dissemination, copying, printing or other use of this e-mail by persons or entities other than the addressee is prohibited. If you have received this e-mail in error, please contact the sender immediately and delete the material from any computer.

using Azure.Identity; using MimeKit; using Microsoft.Graph; using Microsoft.Identity.Client; using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net.Http.Headers; using System.Text; using System.Security; using System.Threading.Tasks; using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices.ComTypes; using Microsoft.Graph.Models; using static System.Net.Mime.MediaTypeNames; using System.Security.Principal; using Microsoft.Kiota.Abstractions; using System.Xml.Linq;

namespace MSGraphUtil { public partial class frmMain : Form { public frmMain() { InitializeComponent(); } private GraphServiceClient graphClient; private static MailFolder rootFolder; private static string ProfilesConfigFileName = ""; private static string selectedFolderId; private static string targetAccount; private static string Header = ""User-Agent", "ArcImp_schdev""; MailFolder selectedFolder = new MailFolder();

    // a list of the import profiles to be loaded in from the persisted objects
    List<MSGraphImportProfile> theMSGImportProfiles;

    //not all Messages found in the search criteria have matching (or any) attachments so those that do are held in a separate list
    List<Microsoft.Graph.Models.Message> emailsWithViableAttachments = new List<Microsoft.Graph.Models.Message>();
    //This is the object windows uses to match filenames against wildcards
    PatternMatcher thePatternMatcher = new PatternMatcher();
    private static TreeNode rootNode;
    string selectedFolderName;
    // to stop the listview selecteditemchange event doing things when it's being updated by the program itself
    private bool dontActionEvent = false;

    private void Form1_Load(object sender, EventArgs e)
    {
        //displays the version number on the form's title bar
        this.Text += System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

        loadSettings();

        // Add two colums to the listviews to hold an icon and a message
        lvwEmails.View = View.Details;
        lvwEmails.Columns.Add("Date Time", 100, HorizontalAlignment.Center);
        lvwEmails.Columns.Add("Subject", lvwEmails.ClientSize.Width - 190, HorizontalAlignment.Left);
        lvwEmails.Columns.Add("# Attachments", 90, HorizontalAlignment.Center);

        //set the date picker to today with time from midnight to nearly midnight
        dtpickFrom.Value = DateTime.Today;
        dtpickTo.Value = dtpickFrom.Value.AddHours(23).AddMinutes(59).AddSeconds(59);

        //to make life easier when logging into mailboxes get the MSGraph Import profiles as they have the uname/pwd

        string svcAssemblyPath = GetServiceInstallPath("MSGraphImport")?.ToLower();
        //if the service isn't installed
        if (string.IsNullOrEmpty(svcAssemblyPath))
        {
            MessageBox.Show("Cannot get MSgraph Import profiles - looks like the MSGraph Import Service is not installed on this machine");
        }
        else
        {
            //indexof is case sensitive and the assembly path's case is whatever was used to install it
            ProfilesConfigFileName = Path.Combine(svcAssemblyPath.Substring(3, svcAssemblyPath.ToLower().IndexOf("msgraphimport.exe") - 3), "MSGraphImportConfig.xml");
        }
        //load the MSG profiles which populates the combo box but populate the credentilas with the ones last used
        LoadtheMSGProfiles();
        txtAccount.Text = Properties.Settings.Default.Account;
        txtPWD.Text = Properties.Settings.Default.Password;
        //if the profile name showing in the combo box doesn't match the email account, blank out the combo to avoid confusing the user
        if (theMSGImportProfiles.Count > 0 && theMSGImportProfiles[cboProfileName.SelectedIndex].AccountName != txtAccount.Text)
        {
            cboProfileName.Text = "";
        }
    }

    private async void btnLogIn_Click(object sender, EventArgs e)
    {
        Cursor = Cursors.WaitCursor;
        txtDisplay.Clear();
        btnDownload.Enabled = false;
        btnListMessages.Enabled = false;
        if (string.IsNullOrEmpty(txtAccount.Text))
        {
            MessageBox.Show("account required");
            Cursor = Cursors.Default;
            return;
        }
        if (string.IsNullOrEmpty(txtPWD.Text) && string.IsNullOrEmpty(txtSecret.Text))
        {
            MessageBox.Show("Either a password or a secret must be entered");
            Cursor = Cursors.Default;
            return;
        }
        SaveSettings();
        if (string.IsNullOrEmpty(txtTenantID.Text) || string.IsNullOrEmpty(txtAppID.Text ))
        {
            MessageBox.Show("Tenant and App ID required");
            Cursor = Cursors.Default;
            return;
        }
        lvwEmails.Items.Clear();
        
        if (string.IsNullOrEmpty(txtSharedAccount.Text.Trim()))
        {
            targetAccount = txtAccount.Text;
        }
        else
        {
            targetAccount = txtSharedAccount.Text;
        }


        graphClient = getSignedInGraphClient(txtAccount.Text , txtPWD.Text, txtTenantID.Text, txtAppID.Text, txtSecret.Text);

        try
        {
            rootFolder = await graphClient
                .Users[targetAccount]
                .MailFolders["msgfolderroot"]
                .GetAsync((requestConfiguration) =>
                {
                    requestConfiguration.Headers.Add("User-Agent", "ArcImp_schdev");
                });

            treeView1.Nodes.Clear();
            TreeNode rootNode = treeView1.Nodes.Add(rootFolder.Id.ToString(), targetAccount);
            await populateTreeView(rootNode, rootFolder,targetAccount);
            treeView1.ExpandAll();
            treeView1.SelectedNode = rootNode;
            Cursor = Cursors.Default;
        }
        catch (Exception ex)
        {
            Cursor = Cursors.Default;
            updateDisplay($"Getting root folder failed:{ex.Message}");
            return;
        }
        updateDisplay($"Signed In to {targetAccount}");
    }
    private async Task populateTreeView(TreeNode thisNode, MailFolder thisFolder, string accountName)
    {
        try
        {
            MailFolderCollectionResponse response = await graphClient
                .Users[accountName]
                .MailFolders[thisFolder.Id]
                .ChildFolders
                .GetAsync();
            List<MailFolder> childFolders = response.Value;
            foreach (MailFolder folder in childFolders)
            {
                // add unique folder.ID as key to the treeview node
                TreeNode newNode = thisNode.Nodes.Add(folder.Id.ToString(), folder.DisplayName);
                //It's turtles all the way down
                await populateTreeView(newNode, folder, accountName );
            }
        }
        catch (UnauthorizedAccessException)
        {
            //sneaky way of handling recursion errors
            Cursor = Cursors.Default;
            return;
        }

    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        SaveSettings();
    }
    private void SaveSettings()
    {
        Properties.Settings.Default.Account = txtAccount.Text;
        Properties.Settings.Default.SharedAccount = txtSharedAccount.Text;
        Properties.Settings.Default.Password = txtPWD.Text;
        Properties.Settings.Default.DownloadFolder = txtDownLoadFolder.Text;
        Properties.Settings.Default.Save();
    }
    private void loadSettings()
    { //every time you create a new version of the program, Windows puts its settings file in a different (obscure) place
        //this stops settings being lost by triggering the upgrade method
        if (Properties.Settings.Default.UpgradeRequired)
        {
            Properties.Settings.Default.Upgrade();
            Properties.Settings.Default.UpgradeRequired = false;
            Properties.Settings.Default.Save();
        }
        txtAccount.Text = Properties.Settings.Default.Account;
        txtPWD.Text = Properties.Settings.Default.Password;
        txtSharedAccount.Text = Properties.Settings.Default.SharedAccount;
        txtDownLoadFolder.Text = Properties.Settings.Default.DownloadFolder;

    }
    public static string GetServiceInstallPath(string serviceName)
    {
        string retVal = "";
        try
        {
            retVal = (string)Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\services\" + serviceName)?.GetValue("ImagePath");
        }
        catch (Exception)
        {
            MessageBox.Show("Could not retrieve service install path - service may not be installed");
        }
        return retVal;
    }
    public void LoadtheMSGProfiles()
    {
        try
        {
            //instantiate the list of profile objects
            theMSGImportProfiles = new List<MSGraphImportProfile>();
            //read the profiles from the serialized XML into the objects list
            SerializationExtensions.DeserializeMSgraphProfile(theMSGImportProfiles, ProfilesConfigFileName);
        }
        catch (Exception eLoadSettings)
        {
            MessageBox.Show("No MSGraph import profiles loaded: " + eLoadSettings.Message);
        }
        if (theMSGImportProfiles.Count != 0)
        {
            //populate the combo box with the profile names
            cboProfileName.BeginUpdate();
            cboProfileName.Items.Clear();
            foreach (MSGraphImportProfile mip in theMSGImportProfiles)
            {
                cboProfileName.Items.Add(mip.ProfileName);
            }
            if (cboProfileName.Items.Count >= 0)
            {
                cboProfileName.SelectedIndex = 0;
                cboProfileName.Text = cboProfileName.Items[0].ToString();
            }
            cboProfileName.EndUpdate();
            
        }
    }
    private void cboProfileName_SelectedIndexChanged(object sender, EventArgs e)
    {
        int ndx = cboProfileName.SelectedIndex;
        txtTenantID.Text = theMSGImportProfiles[ndx].TenantID;
        txtAppID.Text = theMSGImportProfiles[ndx].ClientID;
        txtAccount.Text = theMSGImportProfiles[ndx].AccountName;
        txtPWD.Text = theMSGImportProfiles[ndx].PassWord;
        txtSecret.Text = theMSGImportProfiles[ndx].Secret;
        txtSharedAccount.Text = theMSGImportProfiles[ndx].SharedAccount;
    }
    private async void treeView1_MouseDown(object sender, MouseEventArgs e)
    {
        TreeViewHitTestInfo info = treeView1.HitTest(treeView1.PointToClient(Cursor.Position));
        if (info == null || treeView1.Nodes.Count < 1 || info.Node is null)
        {
            return; 
        }
        selectedFolderId = info.Node.Name;
        //right click on treeview calls contet menu to create/delete folder
        if (e.Button == MouseButtons.Right)
        {
            contextMenuStrip1.Show(treeView1, new Point(e.X, e.Y));
        }
        if (e.Button == MouseButtons.Left) 
        {
            //the clicked node's key (node.name) is the EWS folder ID - an interminably long string of characters
            if (info.Node.Name == selectedFolder.Id)
            {
                return;
            }

            lvwEmails.Items.Clear();

            selectedFolder = await graphClient
                                    .Users[targetAccount]
                                    .MailFolders[info.Node.Name]
                                    .GetAsync();
            
            updateDisplay($"Folder {selectedFolder.DisplayName} selected");
            // you've selected a folder so enable the button that lets you list matching emails
            btnListMessages.Enabled = true;
            //but you've changed folders so, until you've listed and selected emails, you can't move them or download them :Disable those buttons
            btnDownload.Enabled = btnMoveEmails.Enabled = false;

        }
    }

    private async void btnListMessages_Click(object sender, EventArgs e)
    {
        
        Cursor = Cursors.WaitCursor;
        lvwEmails.Items.Clear();
        try
        {
            string displayMsg = "";
            emailsWithViableAttachments.Clear();
            string theFilter = "";
            MessageCollectionResponse  response = new MessageCollectionResponse ();
            displayMsg += (" with dates between " + dtpickFrom.Value.ToString() + " and " + dtpickTo.Value.ToString());
            theFilter += $"(receivedDateTime gt {dtpickFrom.Value.AddSeconds(-1).ToString("yyyy-MM-ddTHH:mm:ssZ")}) and (receivedDateTime lt {dtpickTo.Value.AddSeconds(1).ToString("yyyy-MM-ddTHH:mm:ssZ")})";


            if (!string.IsNullOrEmpty(txtSubject.Text))
            {
                theFilter += $" and contains(subject, '{txtSubject.Text.Trim()}') ";
                displayMsg += $", with \"{ txtSubject.Text.Trim()}\" in the subject";              
            }
            /*else
            {
            }*/
            updateDisplay("Scanning " + selectedFolderName + " for messages " + displayMsg + " and attachments matching " + txtAttachmentFilter.Text.Trim());
            response = await graphClient
                                    .Users[targetAccount]
                                    .MailFolders[selectedFolder.Id]
                                    .Messages
                                    .GetAsync((requestConfiguration) =>
                                    {
                                        requestConfiguration.QueryParameters.Top = 100;
                                        requestConfiguration.QueryParameters.Filter = theFilter;
                                    });

            List<Microsoft.Graph.Models.Message> foundMessages = response.Value;
            ListViewItem newItem;
            // search on filter
            updateDisplay(foundMessages.Count + " Messages found in folder " + selectedFolderName);
            if (foundMessages.Count > 300)
            {
                if (MessageBox.Show("There are " + foundMessages.Count + " to be scanned. It may take forever to scan them. Do you want to continue?", "Warning", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    return;
                }
            }
            int itemCount = 0;
            int scannedEmailCount = 0;
            lvwEmails.BeginUpdate();
            foreach (Microsoft.Graph.Models.Message theMessage in foundMessages)
            {
                updateDisplay($"Scanning Message # {1+(itemCount++)} for matching attachments");
                
                int matchedAttachmentCount = 0; //counts how many match our mask 
                //graphClient = getSignedInGraphClient(txtAccount.Text, txtPWD.Text, txtTenantID.Text, txtAppID.Text, txtSecret.Text);
                var attachmentsResp = await graphClient
                    .Users[targetAccount]
                    .Messages[theMessage.Id]
                    .Attachments
                    .GetAsync();
                List<Attachment> theAttachments = attachmentsResp.Value;
                foreach (var attachment in theAttachments)
                {
                    if (attachment.OdataType != "#microsoft.graph.itemAttachment")
                    {
                        if (isMaskMatch(attachment.Name, txtAttachmentFilter.Text) == true)
                        {
                            matchedAttachmentCount++;
                        }
                    }
                }

                // if the message has at least one viable attachment, add it to the list of emails with viable attachments
                if (matchedAttachmentCount > 0)
                {
                    // add the email item to the list of viable emails
                    emailsWithViableAttachments.Add(theMessage);
                    //no subject comes through as null and kills the app so make a string
                    string theSubject = "<no subject>";
                    if (!String.IsNullOrEmpty(theMessage.Subject))
                    {
                        theSubject = theMessage.Subject.Trim();
                    }
                    // g format is the date format we want - look it up
                    string[] subItems = { theMessage.ReceivedDateTime.ToString(), theSubject, matchedAttachmentCount.ToString() };
                    //add the dtails 
                    ListViewItem thelvItem = new ListViewItem(subItems);
                    newItem = lvwEmails.Items.Add(thelvItem);
                }
                scannedEmailCount++; //so we can boast how many emails we scanned
                System.Windows.Forms.Application.DoEvents();
            }
            lvwEmails.EndUpdate();
            string possessive = emailsWithViableAttachments.Count == 0 ? " have" : (emailsWithViableAttachments.Count > 1 ? " have" : " has");
            updateDisplay(scannedEmailCount + " emails scanned: " + emailsWithViableAttachments.Count.ToString() + possessive + " matching  attachments");

        }
        catch(Exception ex)
        {
            updateDisplay($"getting messages failed: {ex.Message}");
        }
        Cursor = Cursors.Default;
    }
    private bool isMaskMatch(string fileName, string Mask)
    {
        // takes a string containing delimited file masks, turns it into an array and pattern matches filename against each mask
        bool isMatch = false;

        string[] strTemp = Mask.ToLower().Split(new char[] { ',', '|', ',', ';', ':', ' ' });

        for (int i = 0; i < strTemp.Length; i++)
        {
            string s = strTemp[i];
            if (thePatternMatcher.StrictMatchPattern(s, fileName))
            {
                isMatch = true;
            }
        }
        return isMatch;
    }

    private void btnDownload_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(txtDownLoadFolder.Text))
        {
            System.Media.SystemSounds.Beep.Play();
            txtDownLoadFolder.Focus();
            MessageBox.Show("Choose a download folder");
            return;
        }
        if (!System.IO.Directory.Exists(txtDownLoadFolder.Text))
        {
            System.Media.SystemSounds.Beep.Play();
            txtDownLoadFolder.Focus();
            MessageBox.Show("Download folder doesn't exist - choose a real download folder");
            return;
        }
        //listview is multi-select so we use the count of the list of selected items
        for (int i = 0; i < lvwEmails.SelectedItems.Count; i++)
        {
            //selected item in the listview includes its index so we use that as the index into the list of viable items
            updateDisplay("Downloading attachments from email " + emailsWithViableAttachments[lvwEmails.SelectedIndices[i]].Subject);
            downLoadAttachments(emailsWithViableAttachments[lvwEmails.SelectedIndices[i]], txtDownLoadFolder.Text);
        }

        updateDisplay("Download Finished");
        if (chkOpenFolder.Checked)
        {
            System.Diagnostics.Process.Start(txtDownLoadFolder.Text);
        }

    }

    private async void btnMoveEmails_Click(object sender, EventArgs e)
    {
        using (frmFolders frmFolderz = new frmFolders())
        {
            //pass the treeview to the form
            frmFolderz.SetTreeView(this.treeView1);
            DialogResult result = frmFolderz.ShowDialog();
            if (result == DialogResult.OK)
            {
                // if a selection was made set the text box
                if (frmFolderz.SelectionMade)
                {
                    if (selectedFolder.Id.ToString() == frmFolderz.FolderId)
                    {
                        MessageBox.Show("trying to move an email to where it already is, is just silly! Try again");
                        return;
                    }
                }
                for (int i = 0; i < lvwEmails.SelectedItems.Count; i++)
                {
                    updateDisplay("Moving " + emailsWithViableAttachments[lvwEmails.SelectedIndices[i]].Subject + " to " + frmFolderz.FolderName);
                    
                    var requestBody = new Microsoft.Graph.Users.Item.Messages.Item.Move.MovePostRequestBody
                    {
                        DestinationId = frmFolderz.FolderId,
                    };
                    //graphClient = getSignedInGraphClient(txtAccount.Text, txtPWD.Text, txtTenantID.Text, txtAppID.Text, txtSecret.Text);
                    var response = await graphClient
                         .Users[targetAccount]
                         .Messages[emailsWithViableAttachments[lvwEmails.SelectedIndices[i]].Id]
                         .Move
                         .PostAsync(requestBody);
                }
            }
            updateDisplay("Selected Emails moved to " + frmFolderz.FolderName);
        }

        //Remove the email entries you just moved from the list view but switch off the indexchanged event handler
        try
        {
            dontActionEvent = true;
            lvwEmails.BeginUpdate();
            while (lvwEmails.SelectedItems.Count > 0)
            {
                // the indexes change as you remove them so remove the first one on each loop
                lvwEmails.Items.Remove(lvwEmails.SelectedItems[0]);
            }
        }
        finally
        {
            this.lvwEmails.EndUpdate();
            dontActionEvent = false;
        }
        treeView1.Nodes.Clear();
        TreeNode rootNode = treeView1.Nodes.Add(rootFolder.Id.ToString(), targetAccount);
        await populateTreeView(rootNode, rootFolder, targetAccount);
        rootNode.EnsureVisible();
        selectedFolder = rootFolder;
        treeView1.ExpandAll();
        treeView1.HideSelection = false;
        //refreshing the treeview loses the selected node
        btnListMessages.Enabled = false;
    }

    private void lvwEmails_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (dontActionEvent)
        {
            return;
        }
        updateDisplay(lvwEmails.SelectedItems.Count + " emails selected");
        btnDownload.Enabled = btnMoveEmails.Enabled = true;
    }
    private async void downLoadAttachments(Microsoft.Graph.Models.Message theMessage, string downloadPath)
    {

        int x = 0;
        string uniqueFileName;
        //graphClient = getSignedInGraphClient(txtAccount.Text, txtPWD.Text, txtTenantID.Text, txtAppID.Text, txtSecret.Text);
        var response = await graphClient.Users[targetAccount].Messages[theMessage.Id]
            .Attachments
            .GetAsync();
        var attachments = response.Value;

        foreach (Microsoft.Graph.Models.Attachment theAttachment in attachments)
        {
            if (!(theAttachment is FileAttachment))
            {
                updateDisplay("attachment is item");
                continue;
            }
            var fileAttachment = (FileAttachment)theAttachment;
            string fileAttachmentName = Path.GetFileName(GetSafeFilename(fileAttachment.Name)).ToLower();

            // only download attachments that match the file mask    
            if (isMaskMatch(fileAttachmentName, txtAttachmentFilter.Text))
            {
                updateDisplay($"Downloading attachment No. {++x} = {fileAttachmentName}: Attachment type = {theAttachment.ContentType}");

                // p7m is the format for encrypted and signed emails, it's mime format so has to be further decoded
                if (Path.GetExtension(fileAttachmentName).ToLower() == ".p7m")
                {
                    updateDisplay("Attachment is S/MIME format: Attempting to extract images");
                    // convert to stream to load into mime message object
                    var inStream = new MemoryStream(fileAttachment.ContentBytes);
                    var message = MimeMessage.Load(inStream);
                    int imagecount = 0;
                    foreach (var attachment in message.Attachments)
                    {
                        // the mime content has various attachments including signatures we only want pdfs
                        if (attachment.ContentType.MediaSubtype == "pdf" || attachment.ContentType.MediaSubtype == "octet-stream")
                        {
                            ++imagecount;   
                            var part = (MimePart)attachment;
                            uniqueFileName = getUniqueFilename(Path.Combine(downloadPath, part.FileName));
                            using (var OutStream = System.IO.File.Create(uniqueFileName))
                            {
                                part.Content.DecodeTo(OutStream);
                            }
                            updateDisplay($"pdf extracted from {fileAttachmentName} and downloaded as {uniqueFileName}");
                        }
                        // TO DO: what happens if the attachment is a TIF?   }
                    }
                    if (imagecount == 0) 
                    {
                        updateDisplay("No images found in mime content, downloading attachment in original format");
                        //download the file to the chosen download folder.                                    
                        uniqueFileName = getUniqueFilename(Path.Combine(downloadPath, fileAttachmentName));
                        System.IO.File.WriteAllBytes(Path.Combine(downloadPath, uniqueFileName), fileAttachment.ContentBytes);
                        updateDisplay($"Attachment downloaded as {uniqueFileName}");
                    }
                }
                else 
                {
                    //download the file to the chosen download folder.                                    
                    uniqueFileName = getUniqueFilename(Path.Combine(downloadPath, fileAttachmentName));
                    System.IO.File.WriteAllBytes(Path.Combine(downloadPath, uniqueFileName), fileAttachment.ContentBytes);
                    updateDisplay($"Attachment downloaded as {uniqueFileName}" );
                }
               
            }
        }
    }
    public static string GetSafeFilename(string arbitraryString)
    {
        var invalidChars = System.IO.Path.GetInvalidFileNameChars();
        var replaceIndex = arbitraryString.IndexOfAny(invalidChars, 0);
        if (replaceIndex == -1) return arbitraryString;

        var r = new System.Text.StringBuilder();
        var i = 0;

        do
        {
            r.Append(arbitraryString, i, replaceIndex - i);

            switch (arbitraryString[replaceIndex])
            {
                case '"':
                    r.Append("''");
                    break;
                case '<':
                    r.Append('\u02c2'); // '˂' (modifier letter left arrowhead)
                    break;
                case '>':
                    r.Append('\u02c3'); // '˃' (modifier letter right arrowhead)
                    break;
                case '|':
                    r.Append('\u2223'); // '∣' (divides)
                    break;
                case ':':
                    r.Append('-');
                    break;
                case '*':
                    r.Append('\u2217'); // '∗' (asterisk operator)
                    break;
                case '\\':
                case '/':
                    r.Append('\u2044'); // '⁄' (fraction slash)
                    break;
                case '\0':
                case '\f':
                case '?':
                    break;
                case '\t':
                case '\n':
                case '\r':
                case '\v':
                    r.Append(' ');
                    break;
                default:
                    r.Append('_');
                    break;
            }

            i = replaceIndex + 1;
            replaceIndex = arbitraryString.IndexOfAny(invalidChars, i);
        } while (replaceIndex != -1);

        r.Append(arbitraryString, i, arbitraryString.Length - i);

        return r.ToString();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
        {
            txtDownLoadFolder.Text = folderBrowserDialog1.SelectedPath;
        }
    }
    private void updateDisplay(string logText)
    {
        int MaxLength = 150000;
        int nlpos = 0;
        // Get the current text, and append the newText to the end
        string buffer = txtDisplay.Text;
        buffer += logText + Environment.NewLine;

        // Ensure buffer does not exceed maximum length
        if (buffer.Length > MaxLength) // Max Length constant declared elsewhere
        {
            nlpos = buffer.IndexOf('\r');
            if (nlpos > 0)
            {
                buffer = buffer.Substring(nlpos + 2);
            }
        }
        // Update MybufferBox
        txtDisplay.Text = buffer;
        txtDisplay.SelectionStart = txtDisplay.Text.Length;
        txtDisplay.ScrollToCaret();
        txtDisplay.Refresh();
    }

    private async void newFolderToolStripMenuItem_Click(object sender, EventArgs e)
    {
        frmNewFolder frmChoose = new frmNewFolder();
        if (frmChoose.ShowDialog() != DialogResult.OK)
        {
            return;
        }
        try
        {
            var mailFolder = new MailFolder
            {
                DisplayName = frmChoose.newFolderName,
                IsHidden = false
            };

            var response = await graphClient.Users[targetAccount].MailFolders[selectedFolderId].ChildFolders
                .PostAsync(mailFolder);
            updateDisplay($"Folder {frmChoose.newFolderName} created in {selectedFolder.DisplayName}");
        }
        catch (Exception eCreate)
        {
            MessageBox.Show(eCreate.ToString());
        }

        treeView1.Nodes.Clear();
        rootNode = treeView1.Nodes.Add(rootFolder.Id.ToString(), targetAccount);
        await populateTreeView(rootNode, rootFolder, targetAccount);
        treeView1.ExpandAll();
        treeView1.SelectedNode = rootNode;
        treeView1.Focus();  
    }

    private async void deleteFolderToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show("Are you sure you want to delete this mail folder and its content?", "Could be a mistake", MessageBoxButtons.YesNo) == DialogResult.Yes)
        {
            string folderName = selectedFolder.DisplayName;
            
            await graphClient.Users[targetAccount].MailFolders[selectedFolderId]
                .DeleteAsync();
            treeView1.Nodes.Clear();
            rootNode = treeView1.Nodes.Add(rootFolder.Id.ToString(), targetAccount);
            await populateTreeView(rootNode, rootFolder, targetAccount);
            treeView1.ExpandAll();
            treeView1.SelectedNode = rootNode;
            treeView1.Focus();
            updateDisplay($"Folder {folderName}  deleted");
        }
    }

    private async void renameFolderToolStripMenuItem_Click(object sender, EventArgs e)
    {
        string oldFolderName = selectedFolder.DisplayName;
        frmNewFolder frmChoose = new frmNewFolder();
        frmChoose.newFolderName = oldFolderName;
        if (frmChoose.ShowDialog() != DialogResult.OK)
        {
            return;
        }
        try
        {

            var mailFolder = new MailFolder
            {
                DisplayName = frmChoose.newFolderName
            };

            await graphClient
                .Users[targetAccount]
                .MailFolders[selectedFolderId]
                .PatchAsync(mailFolder);
            updateDisplay($"Folder {oldFolderName} renamed to {mailFolder.DisplayName} ");
        }
        catch (Exception eRename)
        {
            MessageBox.Show(eRename.ToString());
        }

        treeView1.Nodes.Clear();
        rootNode = treeView1.Nodes.Add(rootFolder.Id.ToString(), targetAccount);
        await populateTreeView(rootNode, rootFolder, targetAccount);
        treeView1.ExpandAll();
        treeView1.SelectedNode = rootNode;
        treeView1.Focus();
    }
    private string getUniqueFilename(string proposedFileName ) 
    {
        // emails' attachments can have the same name so, if this download conflicts,
        // rename it using (1), (2) etc.
        int i = 0;
        string theUniqeFileName = proposedFileName;
        while (System.IO.File.Exists(theUniqeFileName))
        {
            i++;
            theUniqeFileName = Path.Combine ( Path.GetDirectoryName(proposedFileName),
                Path.GetFileNameWithoutExtension(proposedFileName) + "(" + i.ToString() + ")" + 
                Path.GetExtension(proposedFileName) );
        }
        return theUniqeFileName;
    }
    private GraphServiceClient getSignedInGraphClient(String theAccount, string thePassword, string theTenantID, string theAppID, string theSecret)
    {
        if (!string.IsNullOrEmpty(txtPWD.Text) && string.IsNullOrEmpty(txtSecret.Text))
        {
            //
            var scopes = new[] { "User.Read", "Mail.ReadWrite", "Mail.ReadWrite.Shared", "Mail.Send", "Mail.Send.Shared" };
            // using Azure.Identity;
            //sign in to the MSGraph account 
            var theOptions = new TokenCredentialOptions
            {
                AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
            };

            var userNamePasswordCredential = new UsernamePasswordCredential(theAccount, thePassword, theTenantID, theAppID,theOptions);
           
            return graphClient = new GraphServiceClient(userNamePasswordCredential, scopes);
        }
        else
        {
            //otherwise it's client credential authorisation 
            var scopes = new[] { "https://graph.microsoft.com/.default" };

            // using Azure.Identity;
            var options = new TokenCredentialOptions
            {
                AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
            };

            var clientSecretCredential = new ClientSecretCredential(
                theTenantID, theAppID, theSecret, options);

            return graphClient = new GraphServiceClient(clientSecretCredential, scopes);
        }
    }        
}

}

 namespace MSGraphUtil { partial class frmMain { ///

/// Required designer variable. /// private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmMain));
        this.label6 = new System.Windows.Forms.Label();
        this.label4 = new System.Windows.Forms.Label();
        this.dtpickTo = new System.Windows.Forms.DateTimePicker();
        this.dtpickFrom = new System.Windows.Forms.DateTimePicker();
        this.panel1 = new System.Windows.Forms.Panel();
        this.label11 = new System.Windows.Forms.Label();
        this.txtAttachmentFilter = new System.Windows.Forms.TextBox();
        this.txtSubject = new System.Windows.Forms.TextBox();
        this.label10 = new System.Windows.Forms.Label();
        this.label5 = new System.Windows.Forms.Label();
        this.label8 = new System.Windows.Forms.Label();
        this.cboProfileName = new System.Windows.Forms.ComboBox();
        this.lvwEmails = new System.Windows.Forms.ListView();
        this.button2 = new System.Windows.Forms.Button();
        this.label7 = new System.Windows.Forms.Label();
        this.txtDownLoadFolder = new System.Windows.Forms.TextBox();
        this.btnDownload = new System.Windows.Forms.Button();
        this.btnListMessages = new System.Windows.Forms.Button();
        this.txtPWD = new System.Windows.Forms.TextBox();
        this.label3 = new System.Windows.Forms.Label();
        this.label2 = new System.Windows.Forms.Label();
        this.txtAccount = new System.Windows.Forms.TextBox();
        this.btnLogIn = new System.Windows.Forms.Button();
        this.treeView1 = new System.Windows.Forms.TreeView();
        this.txtDisplay = new System.Windows.Forms.TextBox();
        this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog();
        this.chkOpenFolder = new System.Windows.Forms.CheckBox();
        this.txtSharedAccount = new System.Windows.Forms.TextBox();
        this.label1 = new System.Windows.Forms.Label();
        this.btnMoveEmails = new System.Windows.Forms.Button();
        this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
        this.newFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.deleteFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.renameFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.txtSecret = new System.Windows.Forms.TextBox();
        this.label9 = new System.Windows.Forms.Label();
        this.txtAppID = new System.Windows.Forms.TextBox();
        this.label13 = new System.Windows.Forms.Label();
        this.label14 = new System.Windows.Forms.Label();
        this.txtTenantID = new System.Windows.Forms.TextBox();
        this.panel1.SuspendLayout();
        this.contextMenuStrip1.SuspendLayout();
        this.SuspendLayout();
        // 
        // label6
        // 
        this.label6.AutoSize = true;
        this.label6.Location = new System.Drawing.Point(99, 62);
        this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label6.Name = "label6";
        this.label6.Size = new System.Drawing.Size(30, 16);
        this.label6.TabIndex = 30;
        this.label6.Text = "and";
        // 
        // label4
        // 
        this.label4.AutoSize = true;
        this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
        this.label4.Location = new System.Drawing.Point(146, 2);
        this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label4.Name = "label4";
        this.label4.Size = new System.Drawing.Size(42, 16);
        this.label4.TabIndex = 28;
        this.label4.Text = "Filter";
        // 
        // dtpickTo
        // 
        this.dtpickTo.CustomFormat = "dd/MM/yyyy HH:mm:ss";
        this.dtpickTo.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
        this.dtpickTo.Location = new System.Drawing.Point(141, 57);
        this.dtpickTo.Margin = new System.Windows.Forms.Padding(4);
        this.dtpickTo.Name = "dtpickTo";
        this.dtpickTo.Size = new System.Drawing.Size(194, 22);
        this.dtpickTo.TabIndex = 27;
        this.dtpickTo.Value = new System.DateTime(2001, 1, 1, 0, 0, 0, 0);
        // 
        // dtpickFrom
        // 
        this.dtpickFrom.CustomFormat = "dd/MM/yyyy HH:mm:ss";
        this.dtpickFrom.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
        this.dtpickFrom.Location = new System.Drawing.Point(141, 25);
        this.dtpickFrom.Margin = new System.Windows.Forms.Padding(4);
        this.dtpickFrom.Name = "dtpickFrom";
        this.dtpickFrom.Size = new System.Drawing.Size(194, 22);
        this.dtpickFrom.TabIndex = 26;
        this.dtpickFrom.Value = new System.DateTime(2001, 1, 1, 0, 0, 0, 0);
        // 
        // panel1
        // 
        this.panel1.Controls.Add(this.label11);
        this.panel1.Controls.Add(this.txtAttachmentFilter);
        this.panel1.Controls.Add(this.txtSubject);
        this.panel1.Controls.Add(this.label10);
        this.panel1.Controls.Add(this.label6);
        this.panel1.Controls.Add(this.label5);
        this.panel1.Controls.Add(this.label4);
        this.panel1.Controls.Add(this.dtpickTo);
        this.panel1.Controls.Add(this.dtpickFrom);
        this.panel1.Location = new System.Drawing.Point(4, 239);
        this.panel1.Margin = new System.Windows.Forms.Padding(4);
        this.panel1.Name = "panel1";
        this.panel1.Size = new System.Drawing.Size(348, 191);
        this.panel1.TabIndex = 48;
        // 
        // label11
        // 
        this.label11.AutoSize = true;
        this.label11.Location = new System.Drawing.Point(4, 156);
        this.label11.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label11.Name = "label11";
        this.label11.Size = new System.Drawing.Size(65, 16);
        this.label11.TabIndex = 34;
        this.label11.Text = "File Mask";
        // 
        // txtAttachmentFilter
        // 
        this.txtAttachmentFilter.Location = new System.Drawing.Point(75, 153);
        this.txtAttachmentFilter.Margin = new System.Windows.Forms.Padding(4);
        this.txtAttachmentFilter.Name = "txtAttachmentFilter";
        this.txtAttachmentFilter.Size = new System.Drawing.Size(260, 22);
        this.txtAttachmentFilter.TabIndex = 33;
        this.txtAttachmentFilter.Text = "*.pdf *.tif *.tiff *.p7m";
        // 
        // txtSubject
        // 
        this.txtSubject.Location = new System.Drawing.Point(122, 97);
        this.txtSubject.Margin = new System.Windows.Forms.Padding(4);
        this.txtSubject.Name = "txtSubject";
        this.txtSubject.Size = new System.Drawing.Size(213, 22);
        this.txtSubject.TabIndex = 32;
        // 
        // label10
        // 
        this.label10.AutoSize = true;
        this.label10.Location = new System.Drawing.Point(9, 100);
        this.label10.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label10.Name = "label10";
        this.label10.Size = new System.Drawing.Size(105, 16);
        this.label10.TabIndex = 31;
        this.label10.Text = "Subject contains";
        // 
        // label5
        // 
        this.label5.AutoSize = true;
        this.label5.Location = new System.Drawing.Point(9, 30);
        this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label5.Name = "label5";
        this.label5.Size = new System.Drawing.Size(120, 16);
        this.label5.TabIndex = 29;
        this.label5.Text = "Received between";
        // 
        // label8
        // 
        this.label8.AutoSize = true;
        this.label8.Location = new System.Drawing.Point(77, 10);
        this.label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label8.Name = "label8";
        this.label8.Size = new System.Drawing.Size(45, 16);
        this.label8.TabIndex = 47;
        this.label8.Text = "Profile";
        // 
        // cboProfileName
        // 
        this.cboProfileName.FormattingEnabled = true;
        this.cboProfileName.Location = new System.Drawing.Point(130, 7);
        this.cboProfileName.Margin = new System.Windows.Forms.Padding(4);
        this.cboProfileName.Name = "cboProfileName";
        this.cboProfileName.Size = new System.Drawing.Size(204, 24);
        this.cboProfileName.TabIndex = 46;
        this.cboProfileName.SelectedIndexChanged += new System.EventHandler(this.cboProfileName_SelectedIndexChanged);
        // 
        // lvwEmails
        // 
        this.lvwEmails.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
        | System.Windows.Forms.AnchorStyles.Right)));
        this.lvwEmails.FullRowSelect = true;
        this.lvwEmails.HideSelection = false;
        this.lvwEmails.Location = new System.Drawing.Point(635, 191);
        this.lvwEmails.Margin = new System.Windows.Forms.Padding(4);
        this.lvwEmails.Name = "lvwEmails";
        this.lvwEmails.Size = new System.Drawing.Size(412, 395);
        this.lvwEmails.TabIndex = 45;
        this.lvwEmails.UseCompatibleStateImageBehavior = false;
        this.lvwEmails.View = System.Windows.Forms.View.List;
        this.lvwEmails.SelectedIndexChanged += new System.EventHandler(this.lvwEmails_SelectedIndexChanged);
        // 
        // button2
        // 
        this.button2.Location = new System.Drawing.Point(320, 488);
        this.button2.Margin = new System.Windows.Forms.Padding(4);
        this.button2.Name = "button2";
        this.button2.Size = new System.Drawing.Size(33, 28);
        this.button2.TabIndex = 43;
        this.button2.Text = "...";
        this.button2.UseVisualStyleBackColor = true;
        this.button2.Click += new System.EventHandler(this.button2_Click);
        // 
        // label7
        // 
        this.label7.AutoSize = true;
        this.label7.Location = new System.Drawing.Point(15, 469);
        this.label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label7.Name = "label7";
        this.label7.Size = new System.Drawing.Size(82, 16);
        this.label7.TabIndex = 42;
        this.label7.Text = "Download to";
        // 
        // txtDownLoadFolder
        // 
        this.txtDownLoadFolder.Location = new System.Drawing.Point(15, 491);
        this.txtDownLoadFolder.Margin = new System.Windows.Forms.Padding(4);
        this.txtDownLoadFolder.Name = "txtDownLoadFolder";
        this.txtDownLoadFolder.Size = new System.Drawing.Size(296, 22);
        this.txtDownLoadFolder.TabIndex = 41;
        this.txtDownLoadFolder.Text = "%userprofle%\\downloads";
        // 
        // btnDownload
        // 
        this.btnDownload.Enabled = false;
        this.btnDownload.Location = new System.Drawing.Point(15, 525);
        this.btnDownload.Margin = new System.Windows.Forms.Padding(4);
        this.btnDownload.Name = "btnDownload";
        this.btnDownload.Size = new System.Drawing.Size(339, 27);
        this.btnDownload.TabIndex = 40;
        this.btnDownload.Text = "Download Selected Email\'s Attachments";
        this.btnDownload.UseVisualStyleBackColor = true;
        this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click);
        // 
        // btnListMessages
        // 
        this.btnListMessages.Enabled = false;
        this.btnListMessages.Location = new System.Drawing.Point(12, 433);
        this.btnListMessages.Margin = new System.Windows.Forms.Padding(4);
        this.btnListMessages.Name = "btnListMessages";
        this.btnListMessages.Size = new System.Drawing.Size(340, 31);
        this.btnListMessages.TabIndex = 39;
        this.btnListMessages.Text = "List filtered emails";
        this.btnListMessages.UseVisualStyleBackColor = true;
        this.btnListMessages.Click += new System.EventHandler(this.btnListMessages_Click);
        // 
        // txtPWD
        // 
        this.txtPWD.Location = new System.Drawing.Point(130, 90);
        this.txtPWD.Margin = new System.Windows.Forms.Padding(4);
        this.txtPWD.Name = "txtPWD";
        this.txtPWD.PasswordChar = '*';
        this.txtPWD.Size = new System.Drawing.Size(331, 22);
        this.txtPWD.TabIndex = 38;
        // 
        // label3
        // 
        this.label3.AutoSize = true;
        this.label3.Location = new System.Drawing.Point(55, 93);
        this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label3.Name = "label3";
        this.label3.Size = new System.Drawing.Size(67, 16);
        this.label3.TabIndex = 37;
        this.label3.Text = "Password";
        // 
        // label2
        // 
        this.label2.AutoSize = true;
        this.label2.Location = new System.Drawing.Point(67, 68);
        this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label2.Name = "label2";
        this.label2.Size = new System.Drawing.Size(55, 16);
        this.label2.TabIndex = 36;
        this.label2.Text = "Account";
        // 
        // txtAccount
        // 
        this.txtAccount.Location = new System.Drawing.Point(130, 65);
        this.txtAccount.Margin = new System.Windows.Forms.Padding(4);
        this.txtAccount.Name = "txtAccount";
        this.txtAccount.Size = new System.Drawing.Size(331, 22);
        this.txtAccount.TabIndex = 35;
        // 
        // btnLogIn
        // 
        this.btnLogIn.Location = new System.Drawing.Point(129, 199);
        this.btnLogIn.Margin = new System.Windows.Forms.Padding(4);
        this.btnLogIn.Name = "btnLogIn";
        this.btnLogIn.Size = new System.Drawing.Size(205, 31);
        this.btnLogIn.TabIndex = 32;
        this.btnLogIn.Text = "Sign In";
        this.btnLogIn.UseVisualStyleBackColor = true;
        this.btnLogIn.Click += new System.EventHandler(this.btnLogIn_Click);
        // 
        // treeView1
        // 
        this.treeView1.Location = new System.Drawing.Point(361, 191);
        this.treeView1.Margin = new System.Windows.Forms.Padding(4);
        this.treeView1.Name = "treeView1";
        this.treeView1.Size = new System.Drawing.Size(260, 395);
        this.treeView1.TabIndex = 31;
        this.treeView1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.treeView1_MouseDown);
        // 
        // txtDisplay
        // 
        this.txtDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
        | System.Windows.Forms.AnchorStyles.Right)));
        this.txtDisplay.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
        this.txtDisplay.Location = new System.Drawing.Point(469, 7);
        this.txtDisplay.Margin = new System.Windows.Forms.Padding(4);
        this.txtDisplay.Multiline = true;
        this.txtDisplay.Name = "txtDisplay";
        this.txtDisplay.ScrollBars = System.Windows.Forms.ScrollBars.Both;
        this.txtDisplay.Size = new System.Drawing.Size(578, 180);
        this.txtDisplay.TabIndex = 30;
        // 
        // chkOpenFolder
        // 
        this.chkOpenFolder.AutoSize = true;
        this.chkOpenFolder.Checked = true;
        this.chkOpenFolder.CheckState = System.Windows.Forms.CheckState.Checked;
        this.chkOpenFolder.Location = new System.Drawing.Point(153, 470);
        this.chkOpenFolder.Margin = new System.Windows.Forms.Padding(4);
        this.chkOpenFolder.Name = "chkOpenFolder";
        this.chkOpenFolder.Size = new System.Drawing.Size(190, 20);
        this.chkOpenFolder.TabIndex = 51;
        this.chkOpenFolder.Text = "Open folder after download";
        this.chkOpenFolder.UseVisualStyleBackColor = true;
        // 
        // txtSharedAccount
        // 
        this.txtSharedAccount.Location = new System.Drawing.Point(130, 165);
        this.txtSharedAccount.Margin = new System.Windows.Forms.Padding(4);
        this.txtSharedAccount.Name = "txtSharedAccount";
        this.txtSharedAccount.Size = new System.Drawing.Size(331, 22);
        this.txtSharedAccount.TabIndex = 53;
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(20, 168);
        this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(102, 16);
        this.label1.TabIndex = 52;
        this.label1.Text = "Shared Account";
        // 
        // btnMoveEmails
        // 
        this.btnMoveEmails.Enabled = false;
        this.btnMoveEmails.Location = new System.Drawing.Point(15, 560);
        this.btnMoveEmails.Margin = new System.Windows.Forms.Padding(4);
        this.btnMoveEmails.Name = "btnMoveEmails";
        this.btnMoveEmails.Size = new System.Drawing.Size(339, 27);
        this.btnMoveEmails.TabIndex = 44;
        this.btnMoveEmails.Text = "Move Selected Emails to Another Folder";
        this.btnMoveEmails.UseVisualStyleBackColor = true;
        this.btnMoveEmails.Click += new System.EventHandler(this.btnMoveEmails_Click);
        // 
        // contextMenuStrip1
        // 
        this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
        this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
        this.newFolderToolStripMenuItem,
        this.deleteFolderToolStripMenuItem,
        this.renameFolderToolStripMenuItem});
        this.contextMenuStrip1.Name = "contextMenuStrip1";
        this.contextMenuStrip1.Size = new System.Drawing.Size(179, 76);
        // 
        // newFolderToolStripMenuItem
        // 
        this.newFolderToolStripMenuItem.Name = "newFolderToolStripMenuItem";
        this.newFolderToolStripMenuItem.Size = new System.Drawing.Size(178, 24);
        this.newFolderToolStripMenuItem.Text = "&New Folder";
        this.newFolderToolStripMenuItem.Click += new System.EventHandler(this.newFolderToolStripMenuItem_Click);
        // 
        // deleteFolderToolStripMenuItem
        // 
        this.deleteFolderToolStripMenuItem.Name = "deleteFolderToolStripMenuItem";
        this.deleteFolderToolStripMenuItem.Size = new System.Drawing.Size(178, 24);
        this.deleteFolderToolStripMenuItem.Text = "&Delete Folder";
        this.deleteFolderToolStripMenuItem.Click += new System.EventHandler(this.deleteFolderToolStripMenuItem_Click);
        // 
        // renameFolderToolStripMenuItem
        // 
        this.renameFolderToolStripMenuItem.Name = "renameFolderToolStripMenuItem";
        this.renameFolderToolStripMenuItem.Size = new System.Drawing.Size(178, 24);
        this.renameFolderToolStripMenuItem.Text = "&Rename Folder";
        this.renameFolderToolStripMenuItem.Click += new System.EventHandler(this.renameFolderToolStripMenuItem_Click);
        // 
        // txtSecret
        // 
        this.txtSecret.Location = new System.Drawing.Point(130, 140);
        this.txtSecret.Margin = new System.Windows.Forms.Padding(4);
        this.txtSecret.Name = "txtSecret";
        this.txtSecret.Size = new System.Drawing.Size(331, 22);
        this.txtSecret.TabIndex = 55;
        // 
        // label9
        // 
        this.label9.AutoSize = true;
        this.label9.Location = new System.Drawing.Point(76, 143);
        this.label9.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label9.Name = "label9";
        this.label9.Size = new System.Drawing.Size(46, 16);
        this.label9.TabIndex = 54;
        this.label9.Text = "Secret";
        // 
        // txtAppID
        // 
        this.txtAppID.Location = new System.Drawing.Point(130, 115);
        this.txtAppID.Margin = new System.Windows.Forms.Padding(4);
        this.txtAppID.Name = "txtAppID";
        this.txtAppID.Size = new System.Drawing.Size(331, 22);
        this.txtAppID.TabIndex = 56;
        // 
        // label13
        // 
        this.label13.AutoSize = true;
        this.label13.Location = new System.Drawing.Point(74, 118);
        this.label13.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label13.Name = "label13";
        this.label13.Size = new System.Drawing.Size(48, 16);
        this.label13.TabIndex = 57;
        this.label13.Text = "App ID";
        // 
        // label14
        // 
        this.label14.AutoSize = true;
        this.label14.Location = new System.Drawing.Point(57, 43);
        this.label14.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
        this.label14.Name = "label14";
        this.label14.Size = new System.Drawing.Size(65, 16);
        this.label14.TabIndex = 59;
        this.label14.Text = "Tenant ID";
        // 
        // txtTenantID
        // 

MAlabaster avatar May 04 '23 11:05 MAlabaster