Skip to main content

Overview

The Advanced iMessage Kit SDK supports sending and receiving various types of attachments including images, videos, documents, stickers, and audio messages.

Sending Attachments

1

Prepare the file

Ensure the file exists on your filesystem.
import fs from "fs";
import path from "path";

const filePath = path.join(__dirname, "test-image.png");

if (!fs.existsSync(filePath)) {
  console.error("File not found!");
  process.exit(1);
}
2

Send the attachment

Use the attachments.sendAttachment() method.
const message = await sdk.attachments.sendAttachment({
  chatGuid: "iMessage;-;+1234567890",
  filePath: filePath
});

console.log(`Sent: ${message.guid}`);
3

Check the response

Verify the attachment was sent successfully.
if (message.attachments && message.attachments.length > 0) {
  const attachment = message.attachments[0];
  console.log(`Filename: ${attachment.transferName}`);
  console.log(`MIME type: ${attachment.mimeType}`);
  console.log(`Size: ${(attachment.totalBytes / 1024).toFixed(2)} KB`);
}

Complete Attachment Example

import fs from "fs";
import path from "path";
import { AdvancedIMessageKit } from "@photon-ai/advanced-imessage-kit";

const sdk = new AdvancedIMessageKit({
  serverUrl: "http://localhost:1234",
  apiKey: "your-api-key"
});

const CHAT_GUID = "iMessage;-;+1234567890";
const filePath = path.join(__dirname, "test-image.png");

sdk.on("ready", async () => {
  if (!fs.existsSync(filePath)) {
    console.error(`File not found: ${filePath}`);
    await sdk.close();
    process.exit(1);
  }

  const fileName = path.basename(filePath);
  const fileSize = (fs.statSync(filePath).size / 1024).toFixed(2);
  console.log(`Sending ${fileName} (${fileSize} KB)`);

  try {
    const message = await sdk.attachments.sendAttachment({
      chatGuid: CHAT_GUID,
      filePath: filePath
    });

    console.log(`Sent: ${message.guid}`);
    
    if (message.attachments && message.attachments.length > 0) {
      const att = message.attachments[0];
      console.log(`${att.transferName} (${att.mimeType || "unknown"})`);
    }
  } catch (error) {
    console.error("Failed to send attachment:", error.message);
  }

  await sdk.close();
  process.exit(0);
});

await sdk.connect();

Audio Messages

Send audio files as voice messages with the audio message flag.
import path from "path";

const audioPath = path.join(__dirname, "voice-memo.mp3");

const message = await sdk.attachments.sendAttachment({
  chatGuid: "iMessage;-;+1234567890",
  filePath: audioPath,
  isAudioMessage: true // Renders as audio message in iMessage
});

console.log(`Audio message sent: ${message.guid}`);
console.log(`Created: ${new Date(message.dateCreated).toLocaleString()}`);
Setting isAudioMessage: true automatically enables Private API method for proper audio message rendering in iMessage.

Stickers

Send stickers as standalone messages or attached to existing messages.
Send a sticker as its own message (like sending an image).
import path from "path";

const stickerPath = path.join(__dirname, "sticker.png");

const message = await sdk.attachments.sendSticker({
  chatGuid: "iMessage;-;+1234567890",
  filePath: stickerPath
});

console.log(`Sticker sent: ${message.guid}`);
console.log(`Attachments: ${message.attachments?.length || 0}`);

if (message.attachments?.[0]) {
  const att = message.attachments[0];
  console.log(`MIME type: ${att.mimeType}`);
  console.log(`Is sticker: ${att.isSticker}`);
}
Stickers require Private API to be enabled on your server. They will not work with standard API.

Attachment Replies

Send attachments as replies to specific messages.
import path from "path";

// Original message GUID
const originalMessageGuid = "guid-of-message-to-reply-to";
const imagePath = path.join(__dirname, "reply-image.jpg");

const reply = await sdk.attachments.sendAttachment({
  chatGuid: "iMessage;-;+1234567890",
  filePath: imagePath,
  selectedMessageGuid: originalMessageGuid
});

console.log(`Reply with attachment sent: ${reply.guid}`);
console.log(`Replying to: ${originalMessageGuid}`);

Receiving Attachments

Download and process incoming attachments.
1

Find messages with attachments

Query messages and filter for those with attachments.
const messages = await sdk.messages.getMessages({
  chatGuid: "iMessage;-;+1234567890",
  limit: 50,
  with: ["attachment"]
});

const withAttachments = messages.filter(
  m => m.attachments && m.attachments.length > 0
);

console.log(`Found ${withAttachments.length} messages with attachments`);
2

Get attachment details

Retrieve metadata for a specific attachment.
const firstMsg = withAttachments[0];
const attachment = firstMsg?.attachments?.[0];

if (attachment) {
  console.log(`Attachment: ${attachment.transferName}`);
  console.log(`Type: ${attachment.mimeType || "unknown"}`);
  console.log(`Size: ${(attachment.totalBytes / 1024).toFixed(2)} KB`);
  console.log(`GUID: ${attachment.guid}`);
}
3

Download the attachment

Download the file to your local filesystem.
import fs from "fs";
import path from "path";

const buffer = await sdk.attachments.downloadAttachment(attachment.guid, {
  original: true // Get original quality
});

const outputPath = path.join("/tmp", attachment.transferName);
fs.writeFileSync(outputPath, buffer);

console.log(`Saved to: ${outputPath}`);

Complete Download Example

import fs from "fs";
import path from "path";

const CHAT_GUID = "iMessage;-;+1234567890";
const OUTPUT_DIR = "/tmp";

sdk.on("ready", async () => {
  try {
    // Get recent messages with attachments
    const messages = await sdk.messages.getMessages({
      chatGuid: CHAT_GUID,
      limit: 50,
      with: ["attachment"]
    });

    const messagesWithAttachments = messages.filter(
      m => m.attachments && m.attachments.length > 0
    );

    if (messagesWithAttachments.length === 0) {
      console.log("No messages with attachments found");
      await sdk.close();
      process.exit(0);
    }

    console.log(`Found ${messagesWithAttachments.length} messages with attachments\n`);

    // Download the first attachment
    const firstMsg = messagesWithAttachments[0];
    const attachment = firstMsg?.attachments?.[0];

    if (!attachment) {
      console.log("No attachment found");
      await sdk.close();
      process.exit(0);
    }

    console.log(`Attachment: ${attachment.transferName}`);
    console.log(`Type: ${attachment.mimeType || "unknown"}`);
    console.log(`Size: ${(attachment.totalBytes / 1024).toFixed(2)} KB`);
    console.log(`GUID: ${attachment.guid}\n`);

    // Get attachment info
    const info = await sdk.attachments.getAttachment(attachment.guid);
    console.log(`Info retrieved: ${info.transferName}`);

    // Download attachment
    console.log("Downloading...");
    const buffer = await sdk.attachments.downloadAttachment(attachment.guid, {
      original: true
    });

    const outputPath = path.join(OUTPUT_DIR, attachment.transferName);
    fs.writeFileSync(outputPath, buffer);
    console.log(`Saved to: ${outputPath}`);

    // Get blurhash if it's an image
    if (attachment.mimeType?.startsWith("image/")) {
      try {
        const blurhash = await sdk.attachments.getAttachmentBlurhash(attachment.guid);
        console.log(`Blurhash: ${blurhash}`);
      } catch {
        console.log("Blurhash not available");
      }
    }

    // Check for Live Photo
    if (attachment.hasLivePhoto) {
      console.log("\nDownloading Live Photo video...");
      const liveBuffer = await sdk.attachments.downloadAttachmentLive(attachment.guid);
      const livePath = path.join(OUTPUT_DIR, `${path.parse(attachment.transferName).name}_live.mov`);
      fs.writeFileSync(livePath, liveBuffer);
      console.log(`Live Photo saved to: ${livePath}`);
    }

    // Get total attachment count
    const totalCount = await sdk.attachments.getAttachmentCount();
    console.log(`\nTotal attachments in database: ${totalCount}`);
  } catch (error) {
    console.error("Failed to download attachment:", error);
  }

  await sdk.close();
  process.exit(0);
});

await sdk.connect();

Download Options

Customize how attachments are downloaded.
const buffer = await sdk.attachments.downloadAttachment(attachmentGuid, {
  original: true
});

Live Photos

Download the video component of Live Photos.
import fs from "fs";
import path from "path";

const attachment = message.attachments?.[0];

if (attachment?.hasLivePhoto) {
  console.log("This is a Live Photo!");
  
  // Download the image
  const imageBuffer = await sdk.attachments.downloadAttachment(attachment.guid, {
    original: true
  });
  fs.writeFileSync("live-photo.jpg", imageBuffer);
  
  // Download the video
  const videoBuffer = await sdk.attachments.downloadAttachmentLive(attachment.guid);
  fs.writeFileSync("live-photo.mov", videoBuffer);
  
  console.log("Live Photo downloaded (image + video)");
}

Blurhash

Generate blurhash strings for image placeholders.
const attachment = message.attachments?.[0];

if (attachment?.mimeType?.startsWith("image/")) {
  try {
    const blurhash = await sdk.attachments.getAttachmentBlurhash(attachment.guid);
    console.log(`Blurhash: ${blurhash}`);
    
    // Use blurhash for placeholder while loading full image
  } catch (error) {
    console.log("Blurhash not available for this image");
  }
}
Blurhash is a compact representation of an image placeholder. It’s useful for showing a preview while the full image loads.

Attachment Count

Get the total number of attachments in your database.
const totalAttachments = await sdk.attachments.getAttachmentCount();
console.log(`Total attachments: ${totalAttachments}`);

Listening for New Attachments

Receive attachments in real-time as they arrive.
import fs from "fs";
import path from "path";

sdk.on("new-message", async (message) => {
  // Check if message has attachments
  if (!message.attachments || message.attachments.length === 0) {
    return;
  }

  console.log(`\nNew message with ${message.attachments.length} attachment(s)`);
  
  for (const attachment of message.attachments) {
    console.log(`  - ${attachment.transferName} (${attachment.mimeType})`);
    
    try {
      // Auto-download image attachments
      if (attachment.mimeType?.startsWith("image/")) {
        const buffer = await sdk.attachments.downloadAttachment(attachment.guid, {
          original: true
        });
        
        const savePath = path.join("/tmp/downloads", attachment.transferName);
        fs.writeFileSync(savePath, buffer);
        
        console.log(`    Saved to: ${savePath}`);
      }
    } catch (error) {
      console.error(`    Failed to download: ${error.message}`);
    }
  }
});

Custom Filenames

Specify custom filenames when sending attachments.
import path from "path";

const filePath = path.join(__dirname, "image.jpg");

const message = await sdk.attachments.sendAttachment({
  chatGuid: "iMessage;-;+1234567890",
  filePath: filePath,
  fileName: "vacation-photo.jpg" // Custom filename
});

console.log(`Sent as: ${message.attachments?.[0]?.transferName}`);

Supported File Types

The SDK supports all file types that iMessage supports:
  • Images: JPG, PNG, GIF, HEIC, HEIF
  • Videos: MOV, MP4, M4V
  • Audio: MP3, M4A, WAV, AAC
  • Documents: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
  • Archives: ZIP, RAR
  • Other: Any file type iMessage can handle
Large files may take longer to upload. Consider showing upload progress to users in production applications.

Error Handling

Handle common attachment errors gracefully.
try {
  const message = await sdk.attachments.sendAttachment({
    chatGuid: CHAT_GUID,
    filePath: filePath
  });
  
  console.log("Attachment sent successfully");
} catch (error) {
  if (error.code === "ENOENT") {
    console.error("File not found");
  } else if (error.response?.status === 413) {
    console.error("File too large");
  } else if (error.response?.status === 415) {
    console.error("Unsupported file type");
  } else {
    console.error("Failed to send attachment:", error.message);
  }
}

Next Steps

Sending Messages

Learn more about message sending features

Best Practices

Optimize your attachment handling

Build docs developers (and LLMs) love