Skip to main content

Documentation Index

Fetch the complete documentation index at: https://whatsapp-rust.jlucaso.com/llms.txt

Use this file to discover all available pages before exploring further.

The Newsletter feature provides methods for managing WhatsApp newsletter channels, including creation, subscription management, reactions, and live updates. Newsletter operations use MEX (GraphQL) for metadata/management and IQ stanzas for message operations. Newsletter message sending is handled by the unified client.send_message() method — see the Send API. Reactions remain on the Newsletter struct because they use a different stanza format.
Newsletter messages are plaintext — they are not encrypted with the Signal protocol.

Access

Access newsletter operations through the client:
let newsletter = client.newsletter();

Methods

list_subscribed

List all newsletters the user is subscribed to.
pub async fn list_subscribed(&self) -> Result<Vec<NewsletterMetadata>, MexError>
Returns:
  • Vec<NewsletterMetadata> — List of subscribed newsletters
Example:
let newsletters = client.newsletter().list_subscribed().await?;

for nl in &newsletters {
    println!("{}: {} ({} subscribers)", nl.jid, nl.name, nl.subscriber_count);
}

get_metadata

Fetch metadata for a newsletter by its JID.
pub async fn get_metadata(&self, jid: &Jid) -> Result<NewsletterMetadata, MexError>
Parameters:
  • jid — Newsletter JID (server must be newsletter)
Returns:
  • NewsletterMetadata — Full newsletter metadata
Example:
let metadata = client.newsletter().get_metadata(&newsletter_jid).await?;

println!("Name: {}", metadata.name);
println!("Subscribers: {}", metadata.subscriber_count);
println!("Verified: {:?}", metadata.verification);

get_metadata_by_invite

Fetch metadata for a newsletter by its invite code.
pub async fn get_metadata_by_invite(
    &self,
    invite_code: &str,
) -> Result<NewsletterMetadata, MexError>
Parameters:
  • invite_code — Newsletter invite code string
Returns:
  • NewsletterMetadata — Full newsletter metadata
Example:
let metadata = client.newsletter()
    .get_metadata_by_invite("ABC123")
    .await?;

println!("Found: {} ({})", metadata.name, metadata.jid);

create

Create a new newsletter.
pub async fn create(
    &self,
    name: &str,
    description: Option<&str>,
) -> Result<NewsletterMetadata, MexError>
Parameters:
  • name — Newsletter name
  • description — Optional description
Returns:
  • NewsletterMetadata — Metadata of the newly created newsletter
Example:
let created = client.newsletter()
    .create("My Channel", Some("A description"))
    .await?;

println!("Created: {} ({})", created.name, created.jid);

join

Join (subscribe to) a newsletter.
pub async fn join(&self, jid: &Jid) -> Result<NewsletterMetadata, MexError>
Parameters:
  • jid — Newsletter JID to join
Returns:
  • NewsletterMetadata — Metadata with the viewer’s role set to Subscriber
Example:
let joined = client.newsletter().join(&newsletter_jid).await?;

println!("Joined '{}' as {:?}", joined.name, joined.role);

leave

Leave (unsubscribe from) a newsletter.
pub async fn leave(&self, jid: &Jid) -> Result<(), MexError>
Parameters:
  • jid — Newsletter JID to leave
Example:
client.newsletter().leave(&newsletter_jid).await?;

update

Update a newsletter’s name and/or description.
pub async fn update(
    &self,
    jid: &Jid,
    name: Option<&str>,
    description: Option<&str>,
) -> Result<NewsletterMetadata, MexError>
Parameters:
  • jid — Newsletter JID
  • name — New name, or None to keep the current name
  • description — New description, or None to keep the current description
Returns:
  • NewsletterMetadata — Updated metadata
Example:
let updated = client.newsletter()
    .update(&newsletter_jid, Some("New Name"), None)
    .await?;

println!("Updated: {}", updated.name);

Sending messages

Newsletter message sending is handled by the unified client.send_message() method. See the Send API reference for full details.
use waproto::whatsapp as wa;

let message = wa::Message {
    conversation: Some("Hello subscribers!".to_string()),
    ..Default::default()
};

// Pass a newsletter JID directly to send_message
let msg_id = client.send_message(newsletter_jid, message).await?;
The library detects newsletter recipients automatically and sends messages as plaintext (no Signal encryption), with the correct type and mediatype stanza attributes inferred from the message content. Stanza-level <meta> nodes (for polls, events, etc.) are also included automatically, matching WhatsApp Web behavior.
Newsletter::send_message() was removed. Use client.send_message() instead — it accepts newsletter, group, and direct message JIDs.

send_reaction

Send a reaction to a newsletter message.
pub async fn send_reaction(
    &self,
    jid: &Jid,
    server_id: u64,
    reaction: &str,
) -> Result<(), anyhow::Error>
Parameters:
  • jid — Newsletter JID
  • server_id — Server-assigned ID of the message to react to
  • reaction — Emoji code (e.g., "👍", "❤️"), or empty string to remove
Example:
// Add a reaction
client.newsletter()
    .send_reaction(&newsletter_jid, server_id, "👍")
    .await?;

// Remove a reaction
client.newsletter()
    .send_reaction(&newsletter_jid, server_id, "")
    .await?;

get_messages

Fetch message history from a newsletter.
pub async fn get_messages(
    &self,
    jid: &Jid,
    count: u32,
    before: Option<u64>,
) -> Result<Vec<NewsletterMessage>, anyhow::Error>
Parameters:
  • jid — Newsletter JID
  • count — Maximum number of messages to return
  • before — If set, return messages before this server_id (for pagination)
Returns:
  • Vec<NewsletterMessage> — List of newsletter messages
Example:
// Fetch latest 50 messages
let messages = client.newsletter()
    .get_messages(&newsletter_jid, 50, None)
    .await?;

// Paginate backwards
if let Some(oldest) = messages.last() {
    let older = client.newsletter()
        .get_messages(&newsletter_jid, 50, Some(oldest.server_id))
        .await?;
}

subscribe_live_updates

Subscribe to live updates for a newsletter (reaction counts, message changes).
pub async fn subscribe_live_updates(
    &self,
    jid: &Jid,
) -> Result<u64, anyhow::Error>
Parameters:
  • jid — Newsletter JID
Returns:
  • u64 — Subscription duration in seconds (typically 300)
The server sends Event::NewsletterLiveUpdate events with updated reaction counts. You need to re-subscribe periodically when the duration expires. Example:
let duration = client.newsletter()
    .subscribe_live_updates(&newsletter_jid)
    .await?;

println!("Subscribed for {}s", duration);

Types

NewsletterMetadata

Metadata for a newsletter channel. Implements PartialEq and Eq for direct comparison.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NewsletterMetadata {
    pub jid: Jid,
    pub name: String,
    pub description: Option<String>,
    pub subscriber_count: u64,
    pub verification: NewsletterVerification,
    pub state: NewsletterState,
    pub picture_url: Option<String>,
    pub preview_url: Option<String>,
    pub invite_code: Option<String>,
    pub role: Option<NewsletterRole>,
    pub creation_time: Option<u64>,
}

NewsletterVerification

#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NewsletterVerification {
    Verified,
    Unverified,
}

NewsletterState

#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NewsletterState {
    Active,
    Suspended,
    Geosuspended,
}

NewsletterRole

The viewer’s role in a newsletter.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NewsletterRole {
    Owner,
    Admin,
    Subscriber,
    Guest,
}
All newsletter enums are #[non_exhaustive], so match statements should include a wildcard arm to handle future variants.

NewsletterMessage

A message from a newsletter’s history.
pub struct NewsletterMessage {
    /// Server-assigned message ID (monotonic, used for pagination cursors).
    pub server_id: u64,
    /// Message timestamp (Unix seconds).
    pub timestamp: u64,
    /// Message type (Text, Media, Reaction, etc.).
    pub message_type: NewsletterMessageType,
    /// Whether the viewer is the sender.
    pub is_sender: bool,
    /// Decoded protobuf message (from plaintext bytes).
    pub message: Option<wa::Message>,
    /// Reaction counts on this message.
    pub reactions: Vec<NewsletterReactionCount>,
}

NewsletterMessageType

The type of a newsletter message. Uses a StringEnum for type-safe wire-protocol mapping. Implements PartialEq and Eq.
#[non_exhaustive]
pub enum NewsletterMessageType {
    Text,          // "text"
    Media,         // "media"
    Reaction,      // "reaction"
    Revoke,        // "revoke"
    PollCreation,  // "poll_creation"
    PollVote,      // "poll_vote"
    Edit,          // "edit"
    Other(String), // Unknown/future types
}
Methods:
  • as_str() - Returns the wire-protocol string representation
  • From<&str> - Parse from wire string, unknown values become Other(String)

NewsletterReactionCount

A reaction count on a newsletter message.
pub struct NewsletterReactionCount {
    pub code: String,
    pub count: u64,
}

Error handling

Metadata and management methods return MexError:
pub enum MexError {
    PayloadParsing(String),
    // ... other variants
}
Message operations (send_reaction, get_messages, subscribe_live_updates) return anyhow::Error. Newsletter message sending uses client.send_message() which also returns anyhow::Error.
match client.newsletter().create("Test", None).await {
    Ok(metadata) => println!("Created: {}", metadata.name),
    Err(e) => eprintln!("Failed: {}", e),
}