Python 将exchange文件夹擦除到指定大小

Python 将exchange文件夹擦除到指定大小,python,exchangelib,Python,Exchangelib,我正在尝试删除Exchange文件夹中的邮件,直到文件夹大小达到以字节为单位的指定值 下面是我的示例代码: def get_foldersize(folder): if folder.__class__ != folders.Messages: return -1 return sum(folder.all().values_list('size', flat=True)) def wipe_by_size(folder=account.inbox, size

我正在尝试删除Exchange文件夹中的邮件,直到文件夹大小达到以字节为单位的指定值

下面是我的示例代码:

def get_foldersize(folder):
    if folder.__class__ != folders.Messages:
        return -1
    return sum(folder.all().values_list('size', flat=True))


def wipe_by_size(folder=account.inbox, size='4.8gb', result_as_str=True):
    """
    Delete all old messages in specified exchange folder to specified size
    size may setted like str ("4,9gb", "500.5 Mb", "1024kB") or like int (means size setted in bytes)
    if result_as_str == True, func returns a stats delete msg, 
    otherwise tuple (deleted_files_count, deleted_bytes, before_files_count, before_bytes, after_files_count, after_bytes)
    """
    if folder.__class__ != folders.Messages:
        raise ValueError("Param 'folder' not a exchange-server folder object!")

    m = {
        'gb': 1024 ** 3,
        'mb': 1024 ** 2,
        'kb': 1024,
    }

    size_bytes = None

    if isinstance(size, str):
        if ',' in size:
            size = size.replace(',', '.')

        for k, v in m.items():
            if k in size.lower():
                size = size.split(k)[0].strip()
                try:
                    size_float = float(size)
                    size_bytes = round(size_float * v)
                except ValueError:
                    raise ValueError(f"Incorrect format of param 'size', recieve '{size_str}'")
                break
        else:
            raise ValueError(
                f"Incorrect format of 'size' param, '{size_str}' must contains int or float number and something from '{list(m.keys())}'")
    elif isinstance(size, (int, float,)):
        size_bytes = int(size)
    else:
        raise ValueError(
            'Parameter "size" can be a str (example:"4,9gb", "500.5 Mb", "1024kB") or int folder size in bytes')

    if get_foldersize(folder) < size_bytes:
        return

    before = folder.total_count
    before_bytes = get_foldersize(folder)

    while get_foldersize(folder) > size_bytes:
        msg = folder.all().order_by('datetime_received')[0]
        try:
            # print(msg.subject, msg.sender)
            msg.delete()
        except Exception as e:
            if msg is not None:
                print(f"wipe_by_size: Can't delete {msg.sender}({msg.subject})")
            else:
                print("wipe_by_size: msg = None")

    after = folder.total_count
    deleted = before - after

    after_bytes = get_foldersize(folder)
    deleted_bytes = before_bytes - after_bytes

    if result_as_str:
        return f"""Wiped {deleted} file(s), freed {'{0:12,d}'.format(
            deleted_bytes)} bytes. Before: {before} files, {'{0:12,d}'.format(
            before_bytes)} bytes. After: {after} files, {'{0:12,d}'.format(after_bytes)} bytes"""

    return deleted, deleted_bytes, before, before_bytes, after, after_bytes


delete_msg = wipe_by_size(folder=account.sent, size='4,8gb')
deleted, deleted_bytes, before, before_bytes, after, after_bytes = wipe_by_size(folder=account.sent, size='4,8gb')
def get_foldersize(文件夹):
if文件夹。\uuuuu类\uuuuu!=文件夹。邮件:
返回-1
返回和(folder.all().values_list('size',flat=True))
按大小(folder=account.inbox,size='4.8gb',result=True)定义擦除:
"""
将指定exchange文件夹中的所有旧邮件删除到指定大小
大小可以设置为str(“4,9gb”、“500.5MB”、“1024kB”)或类似int(表示以字节设置的大小)
如果结果_as_str==True,func将返回stats delete消息,
否则元组(已删除的\u文件\u计数、已删除的\u字节、在\u文件\u计数之前、在\u字节之前、在\u文件\u计数之后、在\u字节之后)
"""
if文件夹。\uuuuu类\uuuuu!=文件夹。邮件:
raise VALUERROR(“参数“文件夹”不是exchange server文件夹对象!”)
m={
“gb”:1024**3,
'mb':1024**2,
'kb':1024,
}
大小\字节=无
如果存在(尺寸,str):
如果尺寸为“”,则:
大小=大小。替换(',','。)
对于k,v,单位为m.items():
如果大小为k,则将其降低()
size=size.split(k)[0].strip()
尝试:
大小\浮点数=浮点数(大小)
大小\字节=圆形(大小\浮点*v)
除值错误外:
raise VALUERROR(f“参数'size'的格式不正确,接收'{size\u str}'))
打破
其他:
升值误差(
f“size”参数的格式不正确,{size_str}必须包含int或float数字以及来自“{list(m.keys())}”的内容”
elif isinstance(大小,(整数,浮点,):
大小\字节=int(大小)
其他:
升值误差(
'参数“大小”可以是str(例如:“4,9gb”、“500.5MB”、“1024kB”)或整数文件夹大小(以字节为单位)')
如果获取文件夹大小(文件夹)大小\u字节时:
msg=folder.all().order_by('datetime_received')[0]
尝试:
#打印(msg.subject、msg.sender)
msg.delete()
例外情况除外,如e:
如果msg不是None:
打印(f“按大小擦除:无法删除{msg.sender}({msg.subject})”)
其他:
打印(“按大小擦拭:msg=None”)
after=文件夹总数
删除=之前-之后
之后的字节=获取文件夹大小(文件夹)
已删除的\u字节=前\u字节-后\u字节
如果结果为:
返回f“”已擦除{deleted}文件,释放{{0:12,d}。格式(
已删除{u字节)}字节。之前:{Before}文件,{{0:12,d}。格式(
before_bytes)}字节。before:{After}文件,{{{0:12,d}。格式化(before_bytes)}字节“”
返回已删除、已删除的\u字节、之前、之前\u字节、之后、之后\u字节
按大小删除(文件夹=account.sent,大小=4,8gb)
已删除,已删除字节,之前,之前,之后,之后字节=按大小擦除(文件夹=account.sent,大小='4,8gb')
该功能可以正常工作,但速度非常慢- 缓慢,因为while循环的每次迭代都会调用
get\u foldersize()


我建议我需要以相反的顺序获取文件夹中的所有邮件(如现在),存储每条邮件的大小,然后计算需要一次性擦除和删除的邮件数量和内容。我想那会更快。但是我不知道如何(如果可能的话?)获取消息大小。

正如您所发现的,消息大小包含在
大小
字段中。因此,您可以计算一次文件夹大小,然后读取
msg.size
,并在循环中减小文件夹的总大小。最后,通过仅获取文件夹中每条邮件的
大小
字段来减少网络流量:

class FolderSize(ExtendedProperty):
    property_tag = 0x0e08
    property_type = 'Integer'

Folder.register('size', FolderSize)

folder = account.inbox
folder_size = folder.size
max_size = 123456789  # Bytes

for msg in folder.all().only('size'):
    if folder_size <= max_size:
        break
    msg.delete()
    folder_size -= msg.size
class FolderSize(ExtendedProperty):
属性\标记=0x0e08
属性类型='Integer'
Folder.register('size',FolderSize)
folder=account.inbox
folder\u size=folder.size
最大大小=123456789字节
对于文件夹中的msg.all()。仅('size'):

如果文件夹大小将来会变大,请尝试将代码限制在仍然显示错误的尽可能小的示例中。这里有一些提示,非常感谢!)您能否帮助检查get_foldersize()中的文件夹实例?因为如果文件夹。\uuuu类\uuuu!=folders.Messages:未传递acount.sent文件夹:/n在这种情况下,我建议使用扩展属性直接获取文件夹的大小。我已经更新了上面的示例(FolderSize部分来自exchangelib自述文件)。对不起,Erik,但我担心folder.size返回所有字母的大小,但没有每个字母的附件:,因为我从folder.size和Outlook界面的文件夹属性、文件夹大小窗口中获得的值大不相同。。Outlook报告49451 KB,但folder.size约为70Mb。。我有一个文件夹,里面有许多信件,每个信件至少有一个2-20Mb的附件。。你能帮忙吗?。。我试图在消息中注册PittagAttachSize Canonical属性,但未成功:/thank you!在这种情况下,我只需将各个邮件大小相加即可得到真正的文件夹大小:
sum(folder.all().values_list('size',flat=true))