我使用 MailKit 创建文件夹。这很简单,我可以例如在父文件夹上调用
CreateFolderAsync
(如果我想以异步方式)。
public async Task<IMailFolder> GetOrCreateFolder(string folderName)
{
var rootFolder = await authenticatedClient.GetFolderAsync(imapClient.PersonalNamespaces[0].Path);
var existingFolders = await rootFolder.GetSubfoldersAsync();
var matchingFolder = existingFolders.FirstOrDefault(folder => folder.FullName == folderName);
if (matchingFolder == null)
{
matchingFolder = await rootFolder.CreateAsync(folderName, true);
}
return matchingFolder;
}
但是,如果我传入像
GetOrCreateFolder("folder/subfolder")
或 GetOrCreateFolder("folder.subfolder")
这样的字符串(因为我后来发现许多 IMAP 服务器显然使用 .
作为目录分隔符。这是由服务器在 IMailFolder.DirectorySeparator
中定义/返回的) 例如)。
如果您尝试这样做,两者都会抛出异常(“该名称不是合法的文件夹名称”):
System.ArgumentException
HResult=0x80070057
Nachricht = The name is not a legal folder name. Arg_ParamName_Name
Quelle = MailKit
Stapelüberwachung:
bei MailKit.Net.Imap.ImapFolder.QueueCreateCommand(String name, Boolean isMessageFolder, CancellationToken cancellationToken, String& encodedName)
bei MailKit.Net.Imap.ImapFolder.CreateAsync(String name, Boolean isMessageFolder, CancellationToken cancellationToken)
// ...
Diese Ausnahme wurde ursprünglich von dieser Aufrufliste ausgelöst:
MailKit.Net.Imap.ImapFolder.QueueCreateCommand(string, bool, System.Threading.CancellationToken, out string)
MailKit.Net.Imap.ImapFolder.CreateAsync(string, bool, System.Threading.CancellationToken)
您显然可以硬编码创建第一个文件夹,然后是第二个文件夹,但这确实一点也不灵活。 我的意思是,毕竟,
mkdir
在 Linux 上,例如还支持创建多个文件夹一次,为什么我们不能在这里呢?
那么,我怎样才能完成这项工作呢?
实际上,我有一个答案,我只是“递归地”创建这样一个目录:
private const char directorySeparator = '/';
/// <summary>
/// Gets a folder or sub-folder (recursively). If needed, the folder(s) is/are automatically created.
/// </summary>
/// <param name="folderPath">The full path of the folder to create, separated by slashes (<see cref="directorySeparator"/>).</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task<IMailFolder> GetOrCreateFolder(string folderPath)
{
var rootFolder = await imapClient.GetFolderAsync(imapClient.PersonalNamespaces[0].Path);
return await GetOrCreateFolderRecursiveAsync(rootFolder, folderPath);
}
private async Task<IMailFolder> GetOrCreateFolderRecursiveAsync(IMailFolder parentFolder, string folderPath)
{
if (string.IsNullOrEmpty(folderPath) || folderPath == ".")
return parentFolder;
var (currentFolderName, remainingPath) = SplitCurrentFolderAndRemainingPath(folderPath, [directorySeparator, parentFolder.DirectorySeparator]);
var existingFolders = await parentFolder.GetSubfoldersAsync();
var matchingFolder = existingFolders.FirstOrDefault(folder => folder.Name.Equals(currentFolderName, StringComparison.OrdinalIgnoreCase));
if (matchingFolder == null)
{
logger.LogInformation($"Creating folder {currentFolderName} under {parentFolder.FullName}.");
matchingFolder = await parentFolder.CreateAsync(currentFolderName, true);
}
return await GetOrCreateFolderRecursiveAsync(matchingFolder, remainingPath);
}
private static (string currentFolderName, string remainingPath) SplitCurrentFolderAndRemainingPath(string folderPath,
char[] separator)
{
var parts = folderPath.Split(separator, 2, StringSplitOptions.RemoveEmptyEntries);
var currentFolderName = parts[0];
var remainingPath = parts.Length > 1 ? parts[1] : string.Empty;
return (currentFolderName, remainingPath);
}
它只是假设你有一个已经经过身份验证的
imapClient
又名
ImapClient
当然。 logger
也是可选的。它允许 /
作为硬编码的目录分隔符或来自服务器的
IMailFolder.DirectorySeparator
,我之前已经提到过。 AFAIK,通常是一个 .
又名点。
AFAIK 如果 IMailFolder.DirectorySeparator
出现在您的文件夹中,服务器无论如何都会拒绝它,如上所示,因此在这里拆分它并没有什么坏处。我只实现了异步方式,因为这就是我使用的方式,但显然,同步方式是等效的。