Continuously schedule iMessage or SMS texts with file attachments from your Mac and iPhone.
As long as you have a Mac, this software allows for continuous message scheduling from your iPhone, Mac, and any device that can access the internet (e.g., a Linux machine).
This repo is largely inspired by great work by reidjs, which originally made me realize that this project was possible and whose code serves as the skeleton of this project.
Assuming you have all the setup below this section complete, here is how you use this software.
- Go into Notes app on your Mac or your iPhone.
- Make a note in the "Texts" directory you made earlier.
- At the top of the note put
me now
orme +1m
(schedule for 1 minute in the future). - On the next line, type
Hello World
. - (Optional) Paste an image after that.
- There should be a daemon running on your Mac that will periodically check the Notes app and it should send just fine. There is latency here, as defined by
SETTINGS.txt
in your custom setup.
Below are some examples of what a typical note will look like.
Schedule text for 1 day, 2 hours, and 10 minutes in advance.
kevin_durant +1d2h10m
Hi KD, sorry we defeated you by 30 points.
Not cool on our part rubbing it like this.
I'd just like to let you know that the Suns are so bad that I was confident
enough to schedule this message 1 day, 2 hours, and 10 minutes ago,
which is around the time I thought the third quarter would start (right now)
:) Lebron
Schedule text for January 1, 2025 midnight.
anderson_cooper January 1, 2025 12:00:00 AM
Happy New Year, Anderson!
Sincere apologies that we make you do this show every year.
Equivalently, just replace now
with +0m
.
mom now
My phone is dead, but I plan to be home in 2 hours.
I had to message you with my nifty iTTYL software from my office's Windows
machine by signing into iCloud on Firefox (got the two-factor finished just before it died!)
and making a note in the Notes app.
Then iCloud syncing allowed this message to be sent to you through a daemon on my Mac.
I've kept "Keep Me Signed In" for iCloud on my office Windows machine in case
this ever happens again!
Ned has this setup on his Linux machine too after I told him about this haha.
Neat right?!
I almost forgot, here's a photo of the event today, which I was still able to
include through my iCloud account!
https://share.icloud.com/photos/....
There are three ways to send images ranked from "most general, most annoying" to "least general, least annoying" ways.
- iCloud share link
- Any device
- Mac daemon will go to the link, download the file locally, and send it.
- If the download fails for any reason, the link will itself will be sent.
- The most common reason for failure is rate limiting by iCloud's website, but this is unlikely unless you message a lot or are extending this software.
- "Share" from photos
- iPhone (on Mac too, but use [3] on mac since it's easier)
- Go into Notes app, press camera icon, and share.
- This is necessary due to Apple security restrictions. If you directly
- Make sure iCloud syncing is ON for the Notes app for both your Mac and iPhone.
- Make two folders in your Notes app titled "Texts" and "Sent", and make sure they are recognized as synced folders for iCloud.
- On your Mac,
CMD+Spacebar
and searchPower Nap
- Click the dropdown for
Wake for network access
and select eitherAlways
orOnly on Power Adapter
. If you selectNever
, then texts will only be sent when your Mac is fully on. It is simply a tradeoff of Mac power consumption versus continuity of text scheduling on which setting you choose.
- Open
System Settings
by pressingCMD+Spacebar
, searchingSystem Settings
, and pressingEnter
. - Search
Full disk
inSystem Settings
and clickAllow applications to access all user files
. - Press the
+
sign on the right and give full-disk access to the following apps.- Messages
- Notes
- Terminal
- Clone this repo to your computer
cd private_scheduler
cp SETTINGS_TEMPLATE.txt SETTINGS.txt
and set your preferences (details below).- Open your terminal to this project directory and run these commands in order
virtualenv venv
orconda create -n ittyl python=3.10
source activate.sh
orconda activate ittyl
pip install -r requirements.txt
source .schedulerc
(creates syntactic sugar commands in terminal)addon wake_scheduler
(creates alaunchd
process to periodically scan for new scheduled texts)- Optionally, you can run
addon rwake
if you want to schedule automatic wakes of your Mac (nice fallback when not on power). addon contacts
- Copy and paste the parts of text for contacts that you want into your SETTINGS.txt file. This will give you an alias for phone numbers. Note that underscores are currently necessary but which I hope to refactor out in the near future to make a more user-friendly UI.
addon group_chats
- Sample output will look like
iMessage;+;chatXXXXXXXX contact_name1 contact_name2 XXX-XXX-XXXX (a phone number in a group chat that is not in your contacts)
- Copy only the "iMessage;+;chatXXXX" or "SMS;+;chatXXX" parts (indented, individual contacts are just there to help you distinguish which group chat is which).
- Go into SETTINGS.txt and give it an alias such as
my_group_chat=iMessage;+;chatXXXX
ormy_group_chat=SMS;+;chatXXX
.
- cp
SMS_CONTACTS_TEMPLATE.txt SMS_CONTACTS.txt
. Put the identifiers for non-iPhone users from yourSETTINGS.txt
. There are a few examples in the template for cases to consider so that things do not break.
Make sure to read the SYNC_MODE
row carefully. Its instructions sum up the important nuances of how to use this program pretty well.
Variable | Description | Options / Examples |
---|---|---|
MAX_OVERTIME_MINS |
The maximum minutes allowed for overtime; helps control how much extra time can be accumulated beyond regular scheduling limits. | 10000 minutes |
DEBUG_TEXTING |
Enables or disables debug mode for texting operations; helpful for troubleshooting without sending actual texts. | False (disabled), True (enabled) |
SCHEDULED_TEXTS_DIRECTORY |
The directory where scheduled texts are stored. This path is relative to the script's location. | ./texts |
YOUR_NAME |
The name of the user or the identifier used in the scripts. | your_name |
WAKE_FREQUENCY |
The frequency in minutes at which the scheduler wakes to check if any texts need to be sent. | 15 minutes |
RWAKE_FREQUENCY |
The recovery wake frequency in minutes, used perhaps for a more rapid check in special circumstances. | 1 minute |
OUTPUT_PATH |
The path where output logs from the script are stored. | /tmp/text_scheduler.out |
ABSOLUTE_PYTHON_PATH |
The absolute path to the Python executable used by the script. | ~/anaconda3/bin/python |
SYNC_MODE |
Controls how the texting script synchronizes and schedules texts based on their readiness and specified conditions. - "always" : Texts are scheduled every time the script is called, regardless of their designated times. - "never" : Disables all scheduling; typically used temporarily. - "only_if_ready" or "conditional" : Texts are scheduled only if they are ready to be sent immediately. These are aliases and operate the same way. For example, say you schedule "my_contact_name +1d3h11m" for "send text to contact_name after 1 day, 3 hours, and 11 minutes after the last edit of this note" and after 1 day, 3 hours, and 10 minutes you realize you want to edit something...the file will still be there, unscheduled, for you to edit the text. The last modification time is now updated, so you would need to change it to "my_contact_name +1m" if you want it to be sent at the same time as your original intention, else it will take a TOTAL of 2 days, 3 hours, and 22 minutes to send (+ notation is ALWAYS with respect to LAST MODIFICATION TIME) |
"always" , "never" , "only_if_ready" , "conditional" |
WAKE_BUFFER_TIME |
The buffer time in minutes added around wake events to prevent scheduling conflicts or overlaps. | 30 minutes |
MAX_IDLE_EDIT_TIME |
The maximum time allowed for editing a scheduled text before it is sent, formatted as a string with time units. | 30s |
TODO: Describe the above better or make a youtube video (probably easier this way).