{"id":5308,"library":"markdown-to-confluence","title":"Markdown to Confluence Publisher","description":"markdown-to-confluence is a Python library and command-line tool (md-to-conf) designed to publish Markdown files to Confluence wikis. It parses Markdown, converts its content into Confluence Storage Format (XHTML), and invokes Confluence API endpoints to upload pages and attachments (like images). It supports single-page and directory synchronization modes, handling relative links and page hierarchies. The current version is 0.5.8 and it appears to be actively maintained with a focus on ease of use for documentation synchronization.","status":"active","version":"0.5.8","language":"en","source_language":"en","source_url":"https://github.com/hunyadi/md2conf","tags":["markdown","confluence","documentation","publishing","cli","atlassian"],"install":[{"cmd":"pip install markdown-to-confluence","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Optional: For local rendering of Mermaid diagrams. Install via npm: `npm install -g @mermaid-js/mermaid-cli`.","package":"@mermaid-js/mermaid-cli","optional":true}],"imports":[{"note":"Primary client for interacting with the Confluence API programmatically.","symbol":"ConfluenceClient","correct":"from md_to_conf.client import ConfluenceClient"},{"note":"Used to convert Markdown content into Confluence Storage Format (XHTML).","symbol":"ConfluenceConverter","correct":"from md_to_conf.converter import ConfluenceConverter"}],"quickstart":{"code":"# Create a markdown file named 'my_doc.md'\n# Example content:\n# # My Awesome Documentation\n# This is a paragraph with **bold** text.\n#\n# ## Section 1\n# - Item 1\n# - Item 2\n\nimport os\n\n# Set environment variables for Confluence authentication\n# Replace with your actual values or ensure they are set in your environment\nos.environ['ATLASSIAN_ORGNAME'] = os.environ.get('ATLASSIAN_ORGNAME', 'your_organization') # e.g., 'yourcompany' for yourcompany.atlassian.net\nos.environ['ATLASSIAN_USERNAME'] = os.environ.get('ATLASSIAN_USERNAME', 'your_confluence_email')\nos.environ['ATLASSIAN_API_KEY'] = os.environ.get('ATLASSIAN_API_KEY', 'your_atlassian_api_key')\n\n# To publish 'my_doc.md' to the 'DOC' space in Confluence, using the CLI:\n# Ensure 'md-to-conf' is available in your PATH after installation\n# Example using subprocess (or run directly in your shell):\n\nimport subprocess\n\nmarkdown_file = \"my_doc.md\"\nconfluence_space_key = \"DOC\"\n\n# Create a dummy markdown file for the example\nwith open(markdown_file, \"w\") as f:\n    f.write(\"# My Awesome Documentation\\n\")\n    f.write(\"This is a paragraph with **bold** text.\\n\\n\")\n    f.write(\"## Section 1\\n\")\n    f.write(\"- Item 1\\n\")\n    f.write(\"- Item 2\\n\")\n\nprint(f\"Attempting to publish {markdown_file} to Confluence space {confluence_space_key}...\")\ntry:\n    # Using the command-line interface directly\n    command = [\n        \"md-to-conf\",\n        markdown_file,\n        confluence_space_key,\n        \"--orgname\", os.environ['ATLASSIAN_ORGNAME'],\n        \"--username\", os.environ['ATLASSIAN_USERNAME'],\n        \"--apikey\", os.environ['ATLASSIAN_API_KEY'],\n        \"--verbose\" # Add for detailed output during publishing\n    ]\n    # For security, avoid passing sensitive data directly in `shell=True`\n    process = subprocess.run(command, capture_output=True, text=True, check=True)\n    print(\"Publishing successful (or simulated if --simulate was used).\")\n    print(\"STDOUT:\", process.stdout)\n    print(\"STDERR:\", process.stderr)\nexcept subprocess.CalledProcessError as e:\n    print(f\"Error publishing: {e}\")\n    print(\"STDOUT:\", e.stdout)\n    print(\"STDERR:\", e.stderr)\n    print(\"Hint: Check your Confluence credentials, organization name, and space key.\")\n    print(\"Also ensure the Confluence API key has sufficient permissions.\")\nexcept FileNotFoundError:\n    print(\"Error: 'md-to-conf' command not found. Is markdown-to-confluence installed and in your PATH?\")\n\n# Clean up dummy file\nos.remove(markdown_file)\n","lang":"python","description":"The `markdown-to-confluence` library is primarily used via its command-line interface, `md-to-conf`. This quickstart demonstrates how to publish a single Markdown file to a specified Confluence space using environment variables for authentication. Replace placeholder values with your actual Confluence organization name, username (email), and API key."},"warnings":[{"fix":"Ensure `ATLASSIAN_ORGNAME` (e.g., 'yourcompany' for 'yourcompany.atlassian.net'), `ATLASSIAN_USERNAME`, and a valid `ATLASSIAN_API_KEY` are correctly configured. Verify the API key has necessary permissions to create/update pages in the target space. Refer to Atlassian's documentation for generating API tokens.","message":"Confluence authentication requires your organization domain, username (email), and an API key. These can be supplied via command-line arguments (`--orgname`, `--username`, `--apikey`) or environment variables (`ATLASSIAN_ORGNAME`, `ATLASSIAN_USERNAME`, `ATLASSIAN_API_KEY`). Incorrect credentials or insufficient permissions will result in a 401 Unauthorized error or other access-related failures.","severity":"gotcha","affected_versions":"All"},{"fix":"Double-check the `--space` key and `--ancestor` page title for exact matches (including case and punctuation) against your Confluence instance. Ensure the authenticated user has permissions to view the specified space and ancestor page.","message":"When publishing to a directory or specifying an `--ancestor` page, if the target Confluence space key or the ancestor page title is not found, the tool will exit with an error. Space keys and page titles are case-sensitive.","severity":"gotcha","affected_versions":"All"},{"fix":"For reliable image rendering, especially for diagrams, provide PNG alternatives for SVG images. Consider using Mermaid diagrams with the optional `mmdc` CLI for better rendering, which will be converted to PNG.","message":"Confluence has known issues rendering SVG images (e.g., wrong size, text truncation). `markdown-to-confluence` attempts to mitigate this by checking for a corresponding PNG image in the same directory and publishing it instead if found.","severity":"gotcha","affected_versions":"All"},{"fix":"For documents with inter-page relative links, use the directory publishing mode. Ensure all linked Markdown files are part of the directory being published. External images referenced by absolute URLs retain their original URL.","message":"Relative links in Markdown documents are fully supported only when publishing a *directory* of files (directory mode). All relative links must point to other Markdown files within the synchronized directory hierarchy. In single-page mode, relative links to other local Markdown files are not supported.","severity":"gotcha","affected_versions":"All"},{"fix":"Test complex Markdown features after publishing to ensure they render correctly. Be prepared to adjust Markdown source or Confluence post-conversion if specific formatting is critical. Use verbose logging (`-V` or `--verbose`) for diagnostics.","message":"Confluence's Markdown flavor and storage format can differ from standard GitHub Flavored Markdown (GFM). Certain features like `<details>` (spoilers), local anchors within list items, and specific header ID generation might not convert as expected.","severity":"gotcha","affected_versions":"All"},{"fix":"When publishing new hierarchies, ensure parent pages are established. For existing pages, consider adding explicit `confluence-page-id` comments to Markdown files for robust association. Verify parent-child relationships in Confluence.","message":"The tool uses implicit association (matching titles) or explicit association (`<!-- confluence-page-id: ID -->` comment) to link Markdown files to Confluence pages. If a Confluence page created implicitly lacks a 'trusted ancestor' (i.e., its parent doesn't exist or isn't trusted), subsequent synchronizations can fail.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-13T00:00:00.000Z","next_check":"2026-07-12T00:00:00.000Z"}