-1

Issue: Unable to save file in directory (/root/Notion/Image) when using Cron schedule

This is what my code is trying to do:

  1. Check email
  2. Download image attachment
  3. Store in a directory - root/Notion/Image
  4. Retrieve file path

The script is working when I run it manually in Google Cloud terminal. The problem is when I try to schedule it on Cron, it's unable to access the folder to save the file locally.

This is the error when the script failed and require permission:

Traceback (most recent call last):
  File "Notion/test.py", line 121, in <module>
    path = get_attachments(email.message_from_bytes(msg[0][1]))
  File "Notion/test.py", line 47, in get_attachments
    with open(filePath, 'wb') as f:
PermissionError: [Errno 13] Permission denied: '/root/Notion/Image/3.jpeg'

This is the code to retrieve attachment from email

    def get_attachments(msg):
        for part in msg.walk():
            if part.get_content_maintype()=='multipart':
                continue
            if part.get('Content-Disposition') is None:
                continue
    
            fileName = part.get_filename()
    
            if bool(fileName):
                filePath = os.path.join(attachment_dir, fileName)
                with open(filePath, 'wb') as f:
                    f.write(part.get_payload(decode=True))
                    return str(filePath)

Resolved: The problem is that I shouldn't use root directory since it requires permission. I've changed it to home directory instead.

attachment_dir = '/home/dev_thomas_yang/folder_name/folder_name'

For people who needs to check their home direction, simply run this script.

    from pathlib import Path
    home= str(Path.home())
    
    print(home)

Thanks Triplee for the patience to breakdown my issue despite my sloppy ways of presenting it!

Syscall
  • 19,327
  • 10
  • 37
  • 52
Thomas
  • 9
  • 3
  • The error message suggests that your `cron` job is not being run by `root`; obviously, a regular user should absolutely not be able to write to the system user's home directory under any circumstances. Your question doesn't really contain enough information to properly tell what's going on here; could you please [edit] to indicate exactly which user is running this and what the permissions are on the file? The obvious solution is to just let each user run this in their own respective home directory, and have it create any missing directories if that's a requirement you want to keep. – tripleee Mar 03 '21 at 06:49
  • Hi, thanks for your explanation. This is a VM setup by me and is intended to be used privately only. I'm downloading an email attachment and store it in /root/Notion/image. I'm not sure what's the difference between different system user's...is there any path you suggest I can store the file? Or to provide access to Cron. (updated the page to provide more info) – Thomas Mar 03 '21 at 07:21
  • Uh, you did not clarify this at all. Are you logging in as `root`? What is the output of `whoami` and `id`? – tripleee Mar 03 '21 at 07:23
  • If you log in as `thomas` then your files will be somewhere like `/home/thomas` and owned by `thomas`. If you log in as `root` your files will be in `/root` and your files will be owned by `root`. Users who are not the owner would typically not have write access to files they do not own (though this can in principle be controlled with `chmod`). – tripleee Mar 03 '21 at 07:25
  • As an aside, image attachments by default have an implied disposition of `attachment` so the absence of a `Content-Disposition:` header is not directly an indication that they are inline. If you only need to process messages from a single user or a user base who are all forced to use a client which explicitly adds the disposition header, of course the code will work on those messages. – tripleee Mar 03 '21 at 07:28
  • Hi, I have included this step-by-step doc with a screenshot of how I login to VM via SSH. Hopefully this can answer some of the question you had cause I'm a bit confused with some of the terms you mentioned. https://docs.google.com/document/d/1_qAh-QjenjmY5_V32HMu9YXkETxhLCWLoxEuVx52JHI/edit?usp=sharing – Thomas Mar 03 '21 at 08:19
  • It shows you logged in as `dev_thomas_yang` on a server identifying itself as `thomasyang.net`. Copy/pasting that information into the question instead of having us click through to an image gallery with low-contrast screenshots would be a significant improvement; see also https://meta.stackoverflow.com/questions/303812/discourage-screenshots-of-code-and-or-errors – tripleee Mar 03 '21 at 10:44
  • Possible duplicate of https://stackoverflow.com/questions/22743548/cronjob-not-running – tripleee Mar 03 '21 at 10:59

1 Answers1

1

The easiest fix hands down is to change the code so it doesn't try to write to /root. Have it write to the invoking user's home directory instead.

Your question doesn't show the relevant parts of the code, but just change attachment_dir so it's not an absolute path. Maybe separately take care of creating the directory if it doesn't already exist.

import pathlib
# ...
attachment_dir = pathlib.Path("cron/whatever/attachments").mkdir(parents=True, exist_ok=True)
# ...
for loop in circumstances:
    get_attachments(something)

A better design altogether would be to have get_attachments accept the directory name as a parameter, so you can make this configurable from the code which calls it. Global variables are a nuisance and cause hard-to-debug problems because they hide information which is important for understanding the code, and tricky to change when you try to debug that code and don't know which parts of the code depend on the old value.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • If you have a really old Python version, https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python has equivalent recipes for many versions. – tripleee Mar 03 '21 at 10:53
  • Hi Triplee, just want to say thank you for your help to breakdown the issue! The problem is I've no idea how to find my home directory previously so I tried root instead. Thanks for sharing the guideline on how to post questions. I have updated my question & answer hopefully it'll be easier to read for others. – Thomas Mar 03 '21 at 12:47
  • Hardcoding an absolute path is just making the code harder to move or reuse. I'd advice you to just use what I posted instead. – tripleee Mar 03 '21 at 12:53